.NET için Azure Mobile Apps istemci kitaplığını kullanma
Not
Bu ürün kullanımdan kaldırıldı. .NET 8 veya üzerini kullanan projelerin yerini alması için bkz. Community Toolkit Datasync kitaplığı.
Bu kılavuz, Azure Mobile Apps için .NET istemci kitaplığını kullanarak yaygın senaryoları nasıl gerçekleştirebileceğinizi gösterir. MAUI, Xamarin ve Windows (WPF, UWP ve WinUI) dahil olmak üzere herhangi bir .NET 6 veya .NET Standard 2.0 uygulamasında .NET istemci kitaplığını kullanın.
Azure Mobile Apps'i yeni kullanmaya başlamanız durumunda ilk olarak hızlı başlangıç öğreticilerinden birini tamamlamalısınız:
- AvaloniaUI
- MAUI (Android ve iOS)
- Uno Platform
- Windows (UWP)
- Windows (WinUI3)
- Windows (WPF)
- Xamarin (Android Native)
- Xamarin (iOS Native)
- Xamarin Forms (Android ve iOS)
Not
Bu makale, Microsoft Datasync Framework'ün en son (v6.0) sürümünü kapsar. Eski istemciler için
Desteklenen platformlar
.NET istemci kitaplığı, aşağıdakiler dahil olmak üzere herhangi bir .NET Standard 2.0 veya .NET 6 platformunu destekler:
- Android, iOS ve Windows platformları için .NET MAUI.
- Android API düzeyi 21 ve üzeri (Xamarin ve .NET için Android).
- iOS sürüm 12.0 ve üzeri (.NET için Xamarin ve iOS).
- Evrensel Windows Platformu 19041 ve üzeri derlemeler.
- Windows Presentation Framework (WPF).
- Windows Uygulama SDK'sı (WinUI 3).
- Xamarin.Forms
Ayrıca,
Kurulum ve Önkoşullar
NuGet'ten aşağıdaki kitaplıkları ekleyin:
- Microsoft.Datasync.Client
- Çevrimdışı tablolar kullanılıyorsa Microsoft.Datasync.Client.SQLiteStore
.
Bir platform projesi (örneğin, .NET MAUI) kullanıyorsanız kitaplıkları platform projesine ve paylaşılan herhangi bir projeye eklediğinizden emin olun.
Hizmet istemcisini oluşturma
Aşağıdaki kod, arka uç ve çevrimdışı tablolarla tüm iletişimi koordine etmek için kullanılan hizmet istemcisini oluşturur.
var options = new DatasyncClientOptions
{
// Options set here
};
var client = new DatasyncClient("MOBILE_APP_URL", options);
Önceki kodda MOBILE_APP_URL
değerini ASP.NET Core arka uçURL'si ile değiştirin. İstemci tekil olarak oluşturulmalıdır. Kimlik doğrulama sağlayıcısı kullanılıyorsa, şu şekilde yapılandırılabilir:
var options = new DatasyncClientOptions
{
// Options set here
};
var client = new DatasyncClient("MOBILE_APP_URL", authProvider, options);
Kimlik doğrulama sağlayıcısıyla ilgili diğer ayrıntılar bu belgenin ilerleyen bölümlerinde verilmiştir.
Seçenekler
Aşağıdaki gibi eksiksiz (varsayılan) bir seçenek kümesi oluşturulabilir:
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
Normalde bir HTTP isteği, isteği göndermeden önce kimlik doğrulama sağlayıcısından geçirilerek (şu anda kimliği doğrulanmış kullanıcının Authorization
üst bilgisini ekleyen) yapılır. İsteğe bağlı olarak, daha fazla temsilci işleyicisi ekleyebilirsiniz. Her istek, hizmete gönderilmeden önce temsilci işleyicilerinden geçer. temsilci atama işleyicileri ek üst bilgiler eklemenize, yeniden deneme yapmanıza veya günlüğe kaydetme özellikleri sağlamanıza olanak sağlar.
bu makalenin devamında günlük ve istek üst bilgileri ekleme için temsilci işleyicileri örnekleri.
IdGenerator
Bir varlık çevrimdışı tabloya eklendiğinde, bir kimliği olmalıdır. Kimlik sağlanmayan bir kimlik oluşturulur.
IdGenerator
seçeneği, oluşturulan kimliği uyarlamanıza olanak tanır. Varsayılan olarak, genel olarak benzersiz bir kimlik oluşturulur. Örneğin, aşağıdaki ayar tablo adını ve GUID'yi içeren bir dize oluşturur:
var options = new DatasyncClientOptions
{
IdGenerator = (table) => $"{table}-{Guid.NewGuid().ToString("D").ToUpperInvariant()}"
}
InstallationId
bir InstallationId
ayarlanırsa, belirli bir cihazdaki uygulamanın birleşimini tanımlamak için her istekle birlikte özel bir üst bilgi X-ZUMO-INSTALLATION-ID
gönderilir. Bu üst bilgi günlüklere kaydedilebilir ve uygulamanız için ayrı yükleme sayısını belirlemenize olanak tanır.
InstallationId
kullanıyorsanız, benzersiz yüklemelerin izlenebilmesi için kimlik cihazda kalıcı depolamada depolanmalıdır.
OfflineStore
OfflineStore
, çevrimdışı veri erişimi yapılandırılırken kullanılır. Daha fazla bilgi için bkz.Çevrimdışı tablolarla çalışma
ParallelOperations
Çevrimdışı eşitleme işleminin bir bölümü, kuyruğa alınmış işlemleri uzak sunucuya göndermeyi içerir. Gönderme işlemi tetiklendiğinde, işlemler alındıkları sırayla gönderilir. İsteğe bağlı olarak, bu işlemleri göndermek için en fazla sekiz iş parçacığı kullanabilirsiniz. Paralel işlemler, işlemi daha hızlı tamamlamak için hem istemcide hem de sunucuda daha fazla kaynak kullanır. Birden çok iş parçacığı kullanılırken işlemlerin sunucuya ulaşma sırası garanti edilemez.
SerializerSettings
Veri eşitleme sunucusunda seri hale getirici ayarlarını değiştirdiyseniz, istemcideki SerializerSettings
aynı değişiklikleri yapmanız gerekir. Bu seçenek, kendi seri hale getirici ayarlarınızı belirtmenize olanak tanır.
TableEndpointResolver
Kural gereği, tablolar uzak hizmette /tables/{tableName}
yolunda bulunur (sunucu kodundaki Route
özniteliği tarafından belirtildiği gibi). Ancak, tablolar herhangi bir uç nokta yolunda bulunabilir.
TableEndpointResolver
, tablo adını uzak hizmetle iletişim kurmak için bir yola dönüştüren bir işlevdir.
Örneğin, aşağıdaki varsayımı değiştirerek tüm tabloların /api
altında bulunmasına neden olur:
var options = new DatasyncClientOptions
{
TableEndpointResolver = (table) => $"/api/{table}"
};
UserAgent
Veri eşitleme istemcisi, kitaplığın sürümüne göre uygun bir User-Agent üst bilgi değeri oluşturur. Bazı geliştiriciler, kullanıcı aracısı üst bilgisinin istemci hakkında bilgi sızdırdığı görüşündedir.
UserAgent
özelliğini geçerli herhangi bir üst bilgi değerine ayarlayabilirsiniz.
Uzak tablolarla çalışma
Aşağıdaki bölümde, uzak bir tablodaki kayıtların nasıl aranıp alınıp değiştirileceği ve verilerin nasıl değiştirileceği ayrıntılı olarak anlatlanmıştır. Aşağıdaki konular ele alınmıştır:
- Tablo başvurusu oluşturma
- Sorgu verileri
- Sorgu öğeleri sayma
- Kimlik göre uzak verileri arama
- Uzak sunucuya veri ekleme
- Uzak sunucudaki verileri güncelleştirme
- Uzak sunucudaki verileri silme
- Çakışma çözümü ve iyimser eşzamanlılık
Uzak tablo başvurusu oluşturma
Uzak tablo başvurusu oluşturmak için GetRemoteTable<T>
kullanın:
IRemoteTable<TodoItem> remoteTable = client.GetRemoteTable();
Salt okunur bir tablo döndürmek istiyorsanız IReadOnlyRemoteTable<T>
sürümünü kullanın:
IReadOnlyRemoteTable<TodoItem> remoteTable = client.GetRemoteTable();
Model türünün hizmetten ITableData
sözleşmesini uygulaması gerekir. Gerekli alanları sağlamak için DatasyncClientData
kullanın:
public class TodoItem : DatasyncClientData
{
public string Title { get; set; }
public bool IsComplete { get; set; }
}
DatasyncClientData
nesnesi şunları içerir:
-
Id
(dize) - öğe için genel olarak benzersiz bir kimlik. -
UpdatedAt
(System.DataTimeOffset) - öğenin son güncelleştirilmiş olduğu tarih/saat. -
Version
(dize) - sürüm oluşturma için kullanılan opak bir dize. -
Deleted
(boole) -true
öğe silinir.
Hizmet bu alanları korur. Bu alanları istemci uygulamanızın bir parçası olarak ayarlamayın.
DataTable
özniteliği kullanılarak belirtilebilir:
[DataTable("todoitem")]
public class MyTodoItemClass : DatasyncClientData
{
public string Title { get; set; }
public bool IsComplete { get; set; }
}
Alternatif olarak, GetRemoteTable()
çağrısında tablonun adını belirtin:
IRemoteTable<TodoItem> remoteTable = client.GetRemoteTable("todoitem");
İstemci, URI olarak /tables/{tablename}
yolunu kullanır. Tablo adı aynı zamanda SQLite veritabanındaki çevrimdışı tablonun adıdır.
Desteklenen türler
İlkel türlerin (int, float, dize vb.) yanı sıra, modeller için aşağıdaki türler desteklenir:
-
System.DateTime
- ms doğruluğuna sahip bir ISO-8601 UTC tarih/saat dizesi olarak. -
System.DateTimeOffset
- ms doğruluğuna sahip bir ISO-8601 UTC tarih/saat dizesi olarak. -
System.Guid
- kısa çizgi olarak ayrılmış 32 basamak olarak biçimlendirilir.
Uzak sunucudan veri sorgulama
Uzak tablo LINQ benzeri deyimlerle kullanılabilir, örneğin:
-
.Where()
yan tümcesi ile filtreleme. - Çeşitli
.OrderBy()
yan tümceleriyle sıralama. -
.Select()
ile özellikleri seçme. -
.Skip()
ve.Take()
ile sayfalama.
Sorgudaki öğeleri sayma
Sorgunun döndüreceği öğelerin sayısına ihtiyacınız varsa, bir tabloda .CountItemsAsync()
veya sorguda .LongCountAsync()
kullanabilirsiniz:
// 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();
Bu yöntem sunucuya gidiş dönüşe neden olur. Ayrıca, fazladan gidiş dönüşten kaçınarak bir liste doldurarak (örneğin) bir sayım alabilirsiniz:
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);
}
Tablo içeriğini almak için yapılan ilk istek sonrasında sayı doldurulur.
Tüm verileri döndürme
Veriler IAsyncEnumerablearacılığıyla döndürülür:
var enumerable = remoteTable.ToAsyncEnumerable();
await foreach (var item in enumerable)
{
// Process each item
}
IAsyncEnumerable<T>
farklı bir koleksiyona dönüştürmek için aşağıdaki sonlandırma yan tümcelerinden herhangi birini kullanın:
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();
Arka planda, uzak tablo sonucun disk belleğini sizin için işler. Sorguyu gerçekleştirmek için kaç sunucu tarafı isteği gerektiğinden bağımsız olarak tüm öğeler döndürülür. Bu öğeler sorgu sonuçlarında da kullanılabilir (örneğin, remoteTable.Where(m => m.Rating == "R")
).
Veri eşitleme çerçevesi ayrıca iş parçacığı açısından güvenli bir gözlemlenebilir koleksiyon olan ConcurrentObservableCollection<T>
sağlar. Bu sınıf, normalde bir listeyi yönetmek için ObservableCollection<T>
kullanan kullanıcı arabirimi uygulamaları bağlamında kullanılabilir (örneğin, Xamarin Forms veya MAUI listeleri). Bir ConcurrentObservableCollection<T>
doğrudan bir tablodan veya sorgudan temizleyip yükleyebilirsiniz:
var collection = new ConcurrentObservableCollection<T>();
await remoteTable.ToObservableCollection(collection);
.ToObservableCollection(collection)
kullanılması, tek tek öğeler yerine koleksiyonun tamamı için CollectionChanged
olayını bir kez tetikleyerek yeniden çizme süresinin daha hızlı olmasını sağlar.
ConcurrentObservableCollection<T>
ayrıca koşul temelli değişiklikler de vardır:
// 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);
Öğenin dizini önceden bilinmediğinde, koşul temelli değişiklikler olay işleyicilerinde kullanılabilir.
Verileri filtreleme
Verileri filtrelemek için bir .Where()
yan tümcesi kullanabilirsiniz. Mesela:
var items = await remoteTable.Where(x => !x.IsComplete).ToListAsync();
Filtreleme, IAsyncEnumerable öncesinde hizmette ve IAsyncEnumerable sonrasında istemcide yapılır. Mesela:
var items = (await remoteTable.Where(x => !x.IsComplete).ToListAsync()).Where(x => x.Title.StartsWith("The"));
İlk .Where()
yan tümcesi (yalnızca tamamlanmamış öğeleri döndür) hizmette yürütülürken, ikinci .Where()
yan tümcesi ("The" ile başlayarak) istemcide yürütülür.
Where
yan tümcesi, OData alt kümesine çevrilen işlemleri destekler. İşlemler şunlardır:
- İlişkisel işleçler (
==
,!=
,<
,<=
,>
,>=
), - Aritmetik işleçler (
+
,-
,/
,*
,%
), - Sayı duyarlığı (
Math.Floor
,Math.Ceiling
), - Dize işlevleri (
Length
,Substring
,Replace
,IndexOf
,Equals
,StartsWith
,EndsWith
) (yalnızca sıralı ve sabit kültürler), - Tarih özellikleri (
Year
,Month
,Day
,Hour
,Minute
,Second
), - Bir nesnenin özelliklerine erişme ve
- Bu işlemlerden herhangi birini birleştiren ifadeler.
Verileri sıralama
Verileri sıralamak için bir özellik erişimcisi ile .OrderBy()
, .OrderByDescending()
, .ThenBy()
ve .ThenByDescending()
kullanın.
var items = await remoteTable.OrderBy(x => x.IsComplete).ThenBy(x => x.Title).ToListAsync();
Sıralama, hizmet tarafından gerçekleştirilir. Herhangi bir sıralama yan tümcesinde ifade belirtemezsiniz. bir ifadeye göre sıralamak istiyorsanız istemci tarafı sıralamayı kullanın:
var items = await remoteTable.ToListAsync().OrderBy(x => x.Title.ToLowerCase());
Özellikleri seçme
Hizmetten bir veri alt kümesi döndürebilirsiniz:
var items = await remoteTable.Select(x => new { x.Id, x.Title, x.IsComplete }).ToListAsync();
Veri sayfası döndürme
Disk belleği uygulamak için .Skip()
ve .Take()
kullanarak veri kümesinin bir alt kümesini döndürebilirsiniz:
var pageOfItems = await remoteTable.Skip(100).Take(10).ToListAsync();
Gerçek bir uygulamada, sayfalar arasında gezinmek için bir çağrıyıcı denetimi veya karşılaştırılabilir kullanıcı arabirimi ile önceki örneğe benzer sorguları kullanabilirsiniz.
Şimdiye kadar açıklanan tüm işlevler eklenmiştir, bu nedenle bunları zincirlemeye devam edebiliriz. Zincirlenmiş her çağrı sorgunun daha fazlasını etkiler. Bir örnek daha:
var query = todoTable
.Where(todoItem => todoItem.Complete == false)
.Select(todoItem => todoItem.Text)
.Skip(3).
.Take(3);
List<string> items = await query.ToListAsync();
Kimliğine göre uzak verileri arama
GetItemAsync
işlevi, belirli bir kimlikle veritabanındaki nesneleri aramak için kullanılabilir.
TodoItem item = await remoteTable.GetItemAsync("37BBF396-11F0-4B39-85C8-B319C729AF6D");
Almaya çalıştığınız öğe geçici olarak silinmişse includeDeleted
parametresini kullanmanız gerekir:
// 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);
Uzak sunucuya veri ekleme
Tüm istemci türleri, varsayılan olarak bir dize olanInsertItemAsync
yönteminin nasıl kullanılacağını gösterir. parametresi, .NET nesnesi olarak eklenecek verileri içerir.
var item = new TodoItem { Title = "Text", IsComplete = false };
await remoteTable.InsertItemAsync(item);
// Note that item.Id will now be set
Ekleme sırasında benzersiz bir özel kimlik değeri item
dahil değilse, sunucu bir kimlik oluşturur. Çağrı döndürüldikten sonra nesnesini inceleyerek oluşturulan kimliği alabilirsiniz.
Uzak sunucudaki verileri güncelleştirme
Aşağıdaki kod, aynı kimlikle var olan bir kaydı yeni bilgilerle güncelleştirmek için ReplaceItemAsync
yönteminin nasıl kullanılacağını gösterir.
// In this example, we assume the item has been created from the InsertItemAsync sample
item.IsComplete = true;
await remoteTable.ReplaceItemAsync(todoItem);
Uzak sunucudaki verileri silme
Aşağıdaki kod, var olan bir örneği silmek için DeleteItemAsync
yönteminin nasıl kullanılacağını gösterir.
// In this example, we assume the item has been created from the InsertItemAsync sample
await todoTable.DeleteItemAsync(item);
Çakışma çözümü ve iyimser eşzamanlılık
İki veya daha fazla istemci aynı öğeye aynı anda değişiklik yazabilir. Çakışma algılaması olmadan, son yazma işlemi önceki güncelleştirmelerin üzerine yazar. İyimser eşzamanlılık denetimi her işlemin işlenebileceğini ve bu nedenle herhangi bir kaynak kilitleme kullanmadığını varsayar. İyimser eşzamanlılık denetimi, verileri işlemeden önce başka hiçbir işlemin verileri değiştirmediğini doğrular. Veriler değiştirildiyse işlem geri alınır.
Azure Mobile Apps, Mobil Uygulama arka ucunuzdaki her tablo için tanımlanan version
sistem özelliği sütununu kullanarak her öğede yapılan değişiklikleri izleyerek iyimser eşzamanlılık denetimini destekler. Bir kayıt her güncelleştirildiğinde, Mobile Apps bu kaydın version
özelliğini yeni bir değere ayarlar. Her güncelleştirme isteği sırasında, istekle birlikte gelen kaydın version
özelliği, sunucudaki kaydın aynı özelliğiyle karşılaştırılır. İstekle geçirilen sürüm arka uçla eşleşmiyorsa istemci kitaplığı bir DatasyncConflictException<T>
özel durumu oluşturur. Özel durumla birlikte gelen tür, kaydın sunucu sürümünü içeren arka uçtan alınan kayıttır. Uygulama daha sonra bu bilgileri kullanarak güncelleştirme isteğini arka uçtan doğru version
değeriyle yeniden yürüterek değişiklikleri işlemeye karar verebilir.
DatasyncClientData
temel nesnesi kullanılırken iyimser eşzamanlılık otomatik olarak etkinleştirilir.
İyimser eşzamanlılığı etkinleştirmeye ek olarak, kodunuzda DatasyncConflictException<T>
özel durumunu da yakalamanız gerekir. Güncelleştirilmiş kayda doğru version
uygulayarak çakışmayı çözün ve ardından çağrıyı çözümlenen kayıtla yineleyin. Aşağıdaki kod, algılandıktan sonra yazma çakışmasının nasıl çözüleceğini gösterir:
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();
}
Çevrimdışı tablolarla çalışma
Çevrimdışı tablolar, çevrimdışıyken kullanılacak verileri depolamak için yerel bir SQLite deposu kullanır. Tüm tablo işlemleri uzak sunucu deposu yerine yerel SQLite deposuna karşı gerçekleştirilir.
Microsoft.Datasync.Client.SQLiteStore
her platform projesine ve paylaşılan projelere eklediğinizden emin olun.
Tablo başvurusunun oluşturulabilmesi için önce yerel deponun hazırlanması gerekir:
var store = new OfflineSQLiteStore(Constants.OfflineConnectionString);
store.DefineTable<TodoItem>();
Mağaza tanımlandıktan sonra istemciyi oluşturabilirsiniz:
var options = new DatasyncClientOptions
{
OfflineStore = store
};
var client = new DatasyncClient("MOBILE_URL", options);
Son olarak, çevrimdışı özelliklerin başlatıldığından emin olmanız gerekir:
await client.InitializeOfflineStoreAsync();
Mağaza başlatma normalde istemci oluşturulduktan hemen sonra yapılır.
OfflineConnectionString, hem SQLite veritabanının konumunu hem de veritabanını açmak için kullanılan seçenekleri belirtmek için kullanılan bir URI'dir. Daha fazla bilgi için bkz. SQLite
- Bellek içi önbellek kullanmak için
file:inmemory.db?mode=memory&cache=private
kullanın. - Dosya kullanmak için
file:/path/to/file.db
Dosya için mutlak dosya adını belirtmeniz gerekir. Xamarin kullanıyorsanız, bir yol oluşturmak için Xamarin Essentials Dosya Sistemi Yardımcıları
var dbPath = $"{Filesystem.AppDataDirectory}/todoitems.db";
var store = new OfflineSQLiteStore($"file:/{dbPath}?mode=rwc");
MAUI kullanıyorsanız yol oluşturmak için MAUI Dosya Sistemi Yardımcıları kullanabilirsiniz: Örneğin:
var dbPath = $"{Filesystem.AppDataDirectory}/todoitems.db";
var store = new OfflineSQLiteStore($"file:/{dbPath}?mode=rwc");
Çevrimdışı tablo oluşturma
Tablo başvurusu GetOfflineTable<T>
yöntemi kullanılarak elde edilebilir:
IOfflineTable<TodoItem> table = client.GetOfflineTable<TodoItem>();
Uzak tabloda olduğu gibi, salt okunur bir çevrimdışı tabloyu da kullanıma açabilirsiniz:
IReadOnlyOfflineTable<TodoItem> table = client.GetOfflineTable<TodoItem>();
Çevrimdışı tablo kullanmak için kimlik doğrulaması yapmanız gerekmez. Yalnızca arka uç hizmetiyle iletişim kurarken kimlik doğrulaması yapmanız gerekir.
Çevrimdışı Tabloyu Eşitleme
Çevrimdışı tablolar varsayılan olarak arka uçla eşitlenmez. Eşitleme iki parçaya ayrılır. Değişiklikleri yeni öğeleri indirmekten ayrı olarak gönderebilirsiniz. Mesela:
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"]);
}
}
}
Varsayılan olarak, tüm tablolar artımlı eşitleme kullanır; yalnızca yeni kayıtlar alınır. Her benzersiz sorgu için bir kayıt eklenir (OData sorgusunun MD5 karması oluşturularak oluşturulur).
Not
PullItemsAsync
için ilk bağımsız değişken, cihaza hangi kayıtların çekildiğini gösteren OData sorgusudur. İstemci tarafında karmaşık sorgular oluşturmak yerine hizmeti yalnızca kullanıcıya özgü kayıtları döndürecek şekilde değiştirmek daha iyidir.
Seçeneklerin (PullOptions
nesnesi tarafından tanımlanan) genellikle ayarlanması gerekmez. Seçenekler şunlardır:
-
PushOtherTables
- true olarak ayarlanırsa tüm tablolar gönderilir. -
QueryId
- oluşturulan sorgu yerine kullanılacak belirli bir sorgu kimliği. -
WriteDeltaTokenInterval
: Artımlı eşitlemeyi izlemek için kullanılan delta belirtecinin ne sıklıkta yazılır?
SDK, kayıtları çekmeden önce örtük bir PushAsync()
gerçekleştirir.
Çakışma işleme bir PullAsync()
yönteminde gerçekleşir. Çakışmaları çevrimiçi tablolarla aynı şekilde işleyebilir. Çakışma, ekleme, güncelleştirme veya silme işlemi yerine PullAsync()
çağrıldığında oluşturulur. Birden çok çakışma oluşursa, bunlar tek bir PushFailedException
halinde paketlenmiş olur. Her hatayı ayrı ayrı işleyebilir.
Tüm tablolar için değişiklikleri gönderme
Tüm değişiklikleri uzak sunucuya göndermek için şunu kullanın:
await client.PushTablesAsync();
Tabloların bir alt kümesinde değişiklikleri göndermek için PushTablesAsync()
yöntemine bir IEnumerable<string>
sağlayın:
var tablesToPush = new string[] { "TodoItem", "Notes" };
await client.PushTables(tablesToPush);
Uzak hizmete gönderilmeyi bekleyen işlem sayısını okumak için client.PendingOperations
özelliğini kullanın. Çevrimdışı depo yapılandırılmadığında bu özellik null
.
Karmaşık SQLite sorguları çalıştırma
Çevrimdışı veritabanında karmaşık SQL sorguları yapmanız gerekiyorsa, ExecuteQueryAsync()
yöntemini kullanarak bunu yapabilirsiniz. Örneğin, bir SQL JOIN
deyimi yapmak için dönüş değerinin yapısını gösteren bir JObject
tanımlayın ve ExecuteQueryAsync()
kullanın:
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.
Tanım bir anahtar/değer kümesidir. Anahtarlar SQL sorgusunun döndürdüğü alan adlarıyla eşleşmeli ve değerler beklenen türdeki varsayılan değer olmalıdır. Sayılar (uzun), boole değerleri için false
ve diğer her şey için string.Empty
için 0L
kullanın.
SQLite'in desteklenen bir dizi kısıtlayıcı türü vardır. Tarih/saat, karşılaştırmalara izin vermek için dönem bu yana milisaniye olarak depolanır.
Kullanıcıların kimliğini doğrulama
Azure Mobile Apps, kimlik doğrulama çağrılarını işlemek için bir kimlik doğrulama sağlayıcısı oluşturmanıza olanak tanır. Hizmet istemcisini oluştururken kimlik doğrulama sağlayıcısını belirtin:
AuthenticationProvider authProvider = GetAuthenticationProvider();
var client = new DatasyncClient("APP_URL", authProvider);
Kimlik doğrulaması gerektiğinde, belirteci almak için kimlik doğrulama sağlayıcısı çağrılır. Genel kimlik doğrulama sağlayıcısı hem Yetkilendirme üst bilgisi tabanlı kimlik doğrulaması hem de App Service Kimlik Doğrulaması ve Yetkilendirme tabanlı kimlik doğrulaması için kullanılabilir. Aşağıdaki modeli kullanın:
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 */"
};
}
Kimlik doğrulama belirteçleri bellekte önbelleğe alınır (hiçbir zaman cihaza yazılmasın) ve gerektiğinde yenilenir.
Microsoft kimlik platformunu kullanma
Microsoft kimlik platformu, Microsoft Entra ID ile kolayca tümleştirmenizi sağlar. Microsoft Entra kimlik doğrulamasını uygulama hakkında eksiksiz bir öğretici için hızlı başlangıç öğreticilerine bakın. Aşağıdaki kod, erişim belirtecini alma örneğini gösterir:
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;
}
}
Microsoft kimlik platformunu ASP.NET 6 ile tümleştirme hakkında daha fazla bilgi için Microsoft kimlik platformu belgelerine bakın.
Xamarin Essentials veya MAUI WebAuthenticator kullanma
Azure App Service Kimlik Doğrulaması için Xamarin Essentials WebAuthenticator
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
};
}
azure app service kimlik doğrulaması kullanılırken UserId
ve DisplayName
doğrudan kullanılamaz. Bunun yerine, bilgileri /.auth/me
uç noktasından almak için gecikmeli bir istek sahibi kullanın:
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);
}
}
Gelişmiş konular
Yerel veritabanındaki varlıkları temizleme
Normal işlem altında, varlıkları temizleme gerekli değildir. Eşitleme işlemi silinen varlıkları kaldırır ve yerel veritabanı tabloları için gerekli meta verileri korur. Ancak, veritabanı içindeki varlıkları temizlemenin yararlı olduğu zamanlar vardır. Bu tür senaryolardan biri, çok sayıda varlığı silmeniz gerektiği ve verileri tablodan yerel olarak temizlemenin daha verimli olduğu durumlardır.
Bir tablodan kayıtları temizlemek için table.PurgeItemsAsync()
kullanın:
var query = table.CreateQuery();
var purgeOptions = new PurgeOptions();
await table.PurgeItermsAsync(query, purgeOptions, cancellationToken);
Sorgu, tablodan kaldırılacak varlıkları tanımlar. LINQ kullanarak temizlenecek varlıkları tanımlayın:
var query = table.CreateQuery().Where(m => m.Archived == true);
PurgeOptions
sınıfı temizleme işlemini değiştirmek için ayarlar sağlar:
-
DiscardPendingOperations
, sunucuya gönderilmeyi bekleyen işlem kuyruğundaki tablo için bekleyen işlemleri atar. -
QueryId
işlem için kullanılacak delta belirtecini tanımlamak için kullanılan sorgu kimliğini belirtir. -
TimestampUpdatePolicy
temizleme işleminin sonunda delta belirtecinin nasıl ayarlayabileceğinizi belirtir:-
TimestampUpdatePolicy.NoUpdate
, delta belirtecinin güncelleştirilmemesi gerektiğini gösterir. -
TimestampUpdatePolicy.UpdateToLastEntity
, delta belirtecinin tabloda depolanan son varlık içinupdatedAt
alanına güncelleştirilmesi gerektiğini gösterir. -
TimestampUpdatePolicy.UpdateToNow
, delta belirtecinin geçerli tarih/saate güncelleştirilmesi gerektiğini gösterir. -
TimestampUpdatePolicy.UpdateToEpoch
, delta belirtecinin tüm verileri eşitlemek için sıfırlanması gerektiğini gösterir.
-
Verileri eşitlemek için table.PullItemsAsync()
çağırırken kullandığınız QueryId
değerini kullanın.
QueryId
, temizleme tamamlandığında güncelleştirilecek delta belirtecini belirtir.
İstek üst bilgilerini özelleştirme
Belirli uygulama senaryonuzu desteklemek için Mobil Uygulama arka ucuyla iletişimi özelleştirmeniz gerekebilir. Örneğin, kullanıcıya dönmeden önce her giden isteğe özel bir üst bilgi ekleyebilir veya yanıt durum kodlarını değiştirebilirsiniz. Aşağıdaki örnekte olduğu gibi özel bir DelegatingHandlerkullanın:
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;
}
}
İstek günlüğünü etkinleştirme
İstek günlüğü eklemek için DelegatingHandler da kullanabilirsiniz:
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;
}
}
Eşitleme olaylarını izleme
Eşitleme olayı gerçekleştiğinde, olay client.SynchronizationProgress
olay temsilcisine yayımlanır. Olaylar, eşitleme işleminin ilerleme durumunu izlemek için kullanılabilir. Eşitleme olay işleyicisini aşağıdaki gibi tanımlayın:
client.SynchronizationProgress += (sender, args) => {
// args is of type SynchronizationEventArgs
};
SynchronizationEventArgs
türü aşağıdaki gibi tanımlanır:
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; }
}
args
içindeki özellikler, özellik eşitleme olayıyla ilgili olmadığında null
veya -1
.