Jak používat sadu SDK back-endového serveru ASP.NET Core
Tento článek ukazuje, že musíte nakonfigurovat a použít sadu SDK back-endového serveru ASP.NET Core k vytvoření serveru synchronizace dat.
Podporované platformy
Back-endový server ASP.NET Core podporuje ASP.NET 6.0 nebo novější.
Databázové servery musí splňovat následující kritéria DateTime
a Timestamp
pole typu, které je uloženo s přesností milisekund. Implementace úložiště jsou k dispozici pro Entity Framework Core a LiteDb.
Konkrétní podporu databází najdete v následujících částech:
Vytvoření nového serveru synchronizace dat
Server synchronizace dat používá pro vytvoření serveru normální mechanismy ASP.NET Core. Skládá se ze tří kroků:
- Vytvořte projekt serveru ASP.NET 6.0 (nebo novější).
- Přidání Entity Framework Core
- Přidání služeb synchronizace dat
Informace o vytvoření služby ASP.NET Core pomocí Entity Framework Core najdete v tomto kurzu.
Pokud chcete povolit služby synchronizace dat, musíte přidat následující knihovny NuGet:
- Microsoft.AspNetCore.Datasync
- Microsoft.AspNetCore.Datasync.EFCore pro tabulky založené na Entity Framework Core
- Microsoft.AspNetCore.Datasync.InMemory pro tabulky v paměti.
Upravte soubor Program.cs
. Do všech ostatních definic služby přidejte následující řádek:
builder.Services.AddDatasyncControllers();
Můžete také použít šablonu ASP.NET Core datasync-server
:
# This only needs to be done once
dotnet new -i Microsoft.AspNetCore.Datasync.Template.CSharp
mkdir My.Datasync.Server
cd My.Datasync.Server
dotnet new datasync-server
Šablona obsahuje ukázkový model a kontroler.
Vytvoření kontroleru tabulky pro tabulku SQL
Výchozí úložiště používá Entity Framework Core. Vytvoření kontroleru tabulky je třístupňový proces:
- Vytvořte třídu modelu pro datový model.
- Přidejte třídu modelu do
DbContext
aplikace. - Vytvořte novou
TableController<T>
třídu pro zveřejnění modelu.
Vytvoření třídy modelu
Všechny třídy modelu musí implementovat ITableData
. Každý typ úložiště má abstraktní třídu, která implementuje ITableData
. Úložiště Entity Framework Core používá EntityTableData
:
public class TodoItem : EntityTableData
{
/// <summary>
/// Text of the Todo Item
/// </summary>
public string Text { get; set; }
/// <summary>
/// Is the item complete?
/// </summary>
public bool Complete { get; set; }
}
Rozhraní ITableData
poskytuje ID záznamu spolu s dalšími vlastnostmi pro zpracování služeb synchronizace dat:
UpdatedAt
(DateTimeOffset?
) poskytuje datum poslední aktualizace záznamu.Version
(byte[]
) poskytuje neprůhlenou hodnotu, která se změní při každém zápisu.Deleted
(bool
) je true, pokud je záznam označen k odstranění, ale ještě není vyprázdněn.
Knihovna synchronizace dat tyto vlastnosti udržuje. Neupravujte tyto vlastnosti ve vlastním kódu.
Aktualizace DbContext
Každý model v databázi musí být registrován v souboru DbContext
. Příklad:
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
public DbSet<TodoItem> TodoItems { get; set; }
}
Vytvoření kontroleru tabulky
Kontroler tabulky je specializovaný ApiController
. Tady je minimální kontroler tabulky:
[Route("tables/[controller]")]
public class TodoItemController : TableController<TodoItem>
{
public TodoItemController(AppDbContext context) : base()
{
Repository = new EntityTableRepository<TodoItem>(context);
}
}
Poznámka:
- Kontroler musí mít trasu. Podle konvence jsou tabulky vystaveny na dílčí cestě
/tables
, ale mohou být umístěny kdekoli. Pokud používáte klientské knihovny starší než verze 5.0.0, musí být tabulka dílčí cestou/tables
. - Kontroler musí dědit z
TableController<T>
, kde<T>
je implementaceITableData
implementace pro váš typ úložiště. - Přiřaďte úložiště na základě stejného typu jako váš model.
Implementace úložiště v paměti
Můžete také použít úložiště v paměti bez trvalého úložiště. Přidejte do svého Program.cs
úložiště službu singleton:
IEnumerable<Model> seedData = GenerateSeedData();
builder.Services.AddSingleton<IRepository<Model>>(new InMemoryRepository<Model>(seedData));
Nastavte kontroler tabulky následujícím způsobem:
[Route("tables/[controller]")]
public class ModelController : TableController<Model>
{
public MovieController(IRepository<Model> repository) : base(repository)
{
}
}
Konfigurace možností kontroleru tabulky
Určité aspekty kontroleru můžete nakonfigurovat pomocí TableControllerOptions
:
[Route("tables/[controller]")]
public class MoodelController : TableController<Model>
{
public ModelController(IRepository<Model> repository) : base(repository)
{
Options = new TableControllerOptions { PageSize = 25 };
}
}
Mezi možnosti, které můžete nastavit, patří:
PageSize
(int
výchozí hodnota: 100) je maximální počet položek, které operace dotazu vrátí na jedné stránce.MaxTop
(int
výchozí hodnota: 512000) je maximální počet položek vrácených v operaci dotazu bez stránkování.EnableSoftDelete
(bool
výchozí hodnota: false) povolí obnovitelné odstranění, které místo odstranění z databáze označí položky jako odstraněné. Obnovitelné odstranění umožňuje klientům aktualizovat offline mezipaměť, ale vyžaduje, aby se odstraněné položky vyprázdnily z databáze samostatně.UnauthorizedStatusCode
(int
výchozí hodnota: 401 Neautorizováno) je stavový kód vrácený v případě, že uživatel nemůže provést akci.
Konfigurace přístupových oprávnění
Ve výchozím nastavení může uživatel dělat cokoliv, co chce s entitami v tabulce – vytvářet, číst, aktualizovat a odstraňovat libovolný záznam. Pro jemněji odstupňovanou kontrolu nad autorizací vytvořte třídu, která implementuje IAccessControlProvider
. K IAccessControlProvider
implementaci autorizace se používají tři metody:
GetDataView()
vrátí lambda, která omezuje, co vidí připojený uživatel.IsAuthorizedAsync()
určuje, jestli připojený uživatel může provést akci u konkrétní požadované entity.PreCommitHookAsync()
upraví jakoukoli entitu bezprostředně před zápisem do úložiště.
Mezi těmito třemi metodami můžete efektivně zvládnout většinu případů řízení přístupu. Pokud potřebujete přístup k nástroji HttpContextAccessor, nakonfigurujte hoHttpContext
.
Například následující tabulka implementuje osobní tabulku, kde uživatel vidí jenom svoje vlastní záznamy.
public class PrivateAccessControlProvider<T>: IAccessControlProvider<T>
where T : ITableData
where T : IUserId
{
private readonly IHttpContextAccessor _accessor;
public PrivateAccessControlProvider(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
private string UserId { get => _accessor.HttpContext.User?.Identity?.Name; }
public Expression<Func<T,bool>> GetDataView()
{
return (UserId == null)
? _ => false
: model => model.UserId == UserId;
}
public Task<bool> IsAuthorizedAsync(TableOperation op, T entity, CancellationToken token = default)
{
if (op == TableOperation.Create || op == TableOperation.Query)
{
return Task.FromResult(true);
}
else
{
return Task.FromResult(entity?.UserId != null && entity?.UserId == UserId);
}
}
public virtual Task PreCommitHookAsync(TableOperation operation, T entity, CancellationToken token = default)
{
entity.UserId == UserId;
return Task.CompletedTask;
}
}
Metody jsou asynchronní v případě, že potřebujete provést další vyhledávání databáze, abyste získali správnou odpověď. Rozhraní můžete implementovat IAccessControlProvider<T>
na kontroleru, ale přesto musíte předat IHttpContextAccessor
přístup k HttpContext
vláknu bezpečným způsobem.
Pokud chcete použít tohoto zprostředkovatele řízení přístupu, aktualizujte ho TableController
následujícím způsobem:
[Authorize]
[Route("tables/[controller]")]
public class ModelController : TableController<Model>
{
public ModelsController(AppDbContext context, IHttpContextAccessor accessor) : base()
{
AccessControlProvider = new PrivateAccessControlProvider<Model>(accessor);
Repository = new EntityTableRepository<Model>(context);
}
}
Pokud chcete povolit neověřený i ověřený přístup k tabulce, vyzdobit ho [AllowAnonymous]
místo [Authorize]
.
Konfigurace protokolování
Protokolování se zpracovává prostřednictvím normálního mechanismu protokolování pro ASP.NET Core. ILogger
Přiřaďte objekt vlastnostiLogger
:
[Authorize]
[Route("tables/[controller]")]
public class ModelController : TableController<Model>
{
public ModelController(AppDbContext context, Ilogger<ModelController> logger) : base()
{
Repository = new EntityTableRepository<Model>(context);
Logger = logger;
}
}
Monitorování změn úložiště
Když se úložiště změní, můžete aktivovat pracovní postupy, protokolovat odpověď klientovi nebo provádět jinou práci v jedné ze dvou metod:
Možnost 1: Implementace postCommitHookAsync
Rozhraní IAccessControlProvider<T>
poskytuje metodu PostCommitHookAsync()
. Metoda Th PostCommitHookAsync()
je volána po zápisu dat do úložiště, ale před vrácením dat klientovi. Je třeba dbát na to, aby se v této metodě nezměnila data vrácená klientovi.
public class MyAccessControlProvider<T> : AccessControlProvider<T> where T : ITableData
{
public override async Task PostCommitHookAsync(TableOperation op, T entity, CancellationToken cancellationToken = default)
{
// Do any work you need to here.
// Make sure you await any asynchronous operations.
}
}
Tuto možnost použijte, pokud spouštíte asynchronní úlohy jako součást háku.
Možnost 2: Použití obslužné rutiny události RepositoryUpdated
Základní TableController<T>
třída obsahuje obslužnou rutinu události, která je volána současně s metodou PostCommitHookAsync()
.
[Authorize]
[Route(tables/[controller])]
public class ModelController : TableController<Model>
{
public ModelController(AppDbContext context) : base()
{
Repository = new EntityTableRepository<Model>(context);
RepositoryUpdated += OnRepositoryUpdated;
}
internal void OnRepositoryUpdated(object sender, RepositoryUpdatedEventArgs e)
{
// The RepositoryUpdatedEventArgs contains Operation, Entity, EntityName
}
}
Povolení identity služby Aplikace Azure
Server pro synchronizaci dat ASP.NET Core podporuje ASP.NET Základní identitu nebo jakékoli jiné schéma ověřování a autorizace, které chcete podporovat. Abychom vám pomohli s upgrady z předchozích verzí Azure Mobile Apps, poskytujeme také zprostředkovatele identity, který implementuje identitu služby Aplikace Azure. Pokud chcete ve své aplikaci nakonfigurovat identitu služby Aplikace Azure, upravteProgram.cs
:
builder.Services.AddAuthentication(AzureAppServiceAuthentication.AuthenticationScheme)
.AddAzureAppServiceAuthentication(options => options.ForceEnable = true);
// Then later, after you have created the app
app.UseAuthentication();
app.UseAuthorization();
Podpora databází
Entity Framework Core nenastavuje generování hodnot pro sloupce s datem a časem. (Viz Generování hodnot data a času) Úložiště Azure Mobile Apps pro Entity Framework Core automaticky aktualizuje UpdatedAt
pole za vás. Pokud se ale vaše databáze aktualizuje mimo úložiště, musíte zajistit UpdatedAt
aktualizaci polí a Version
polí.
Azure SQL
Vytvořte trigger pro každou entitu:
CREATE OR ALTER TRIGGER [dbo].[TodoItems_UpdatedAt] ON [dbo].[TodoItems]
AFTER INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE
[dbo].[TodoItems]
SET
[UpdatedAt] = GETUTCDATE()
WHERE
[Id] IN (SELECT [Id] FROM INSERTED);
END
Tento trigger můžete nainstalovat buď pomocí migrace, nebo bezprostředně po EnsureCreated()
vytvoření databáze.
Azure Cosmos DB
Azure Cosmos DB je plně spravovaná databáze NoSQL pro vysoce výkonné aplikace libovolné velikosti nebo škálování. Informace o používání služby Azure Cosmos DB s Entity Framework Core najdete v tématu Zprostředkovatel služby Azure Cosmos DB. Při používání služby Azure Cosmos DB s Azure Mobile Apps:
Nastavte kontejner Cosmos pomocí složeného indexu
UpdatedAt
, který určuje pole aId
pole. Složené indexy je možné přidat do kontejneru prostřednictvím webu Azure Portal, ARM, Bicep, Terraformu nebo kódu. Tady je příklad definice prostředku bicep :resource cosmosContainer 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2023-04-15' = { name: 'TodoItems' parent: cosmosDatabase properties: { resource: { id: 'TodoItems' partitionKey: { paths: [ '/Id' ] kind: 'Hash' } indexingPolicy: { indexingMode: 'consistent' automatic: true includedPaths: [ { path: '/*' } ] excludedPaths: [ { path: '/"_etag"/?' } ] compositeIndexes: [ [ { path: '/UpdatedAt' order: 'ascending' } { path: '/Id' order: 'ascending' } ] ] } } } }
Pokud stáhnete podmnožinu položek v tabulce, ujistěte se, že jste zadali všechny vlastnosti zahrnuté v dotazu.
Odvozujte modely z
ETagEntityTableData
třídy:public class TodoItem : ETagEntityTableData { public string Title { get; set; } public bool Completed { get; set; } }
Přidejte metodu
OnModelCreating(ModelBuilder)
do objektuDbContext
. Ovladač cosmos DB pro Entity Framework umístí všechny entity do stejného kontejneru ve výchozím nastavení. Minimálně musíte vybrat vhodný klíč oddílu a zajistit, abyEntityTag
byla vlastnost označena jako značka souběžnosti. Následující fragment kódu například ukládáTodoItem
entity do vlastního kontejneru s odpovídajícím nastavením pro Azure Mobile Apps:protected override void OnModelCreating(ModelBuilder builder) { builder.Entity<TodoItem>(builder => { // Store this model in a specific container. builder.ToContainer("TodoItems"); // Do not include a discriminator for the model in the partition key. builder.HasNoDiscriminator(); // Set the partition key to the Id of the record. builder.HasPartitionKey(model => model.Id); // Set the concurrency tag to the EntityTag property. builder.Property(model => model.EntityTag).IsETagConcurrency(); }); base.OnModelCreating(builder); }
Azure Cosmos DB je podporována v Microsoft.AspNetCore.Datasync.EFCore
balíčku NuGet od verze 5.0.11. Další informace najdete na následujících odkazech:
- Ukázka služby Cosmos DB
- Dokumentace k poskytovateli AZURE Cosmos DB EF Core
- Dokumentace k zásadám indexu služby Cosmos DB
PostgreSQL
Vytvořte trigger pro každou entitu:
CREATE OR REPLACE FUNCTION todoitems_datasync() RETURNS trigger AS $$
BEGIN
NEW."UpdatedAt" = NOW() AT TIME ZONE 'UTC';
NEW."Version" = convert_to(gen_random_uuid()::text, 'UTF8');
RETURN NEW
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE TRIGGER
todoitems_datasync
BEFORE INSERT OR UPDATE ON
"TodoItems"
FOR EACH ROW EXECUTE PROCEDURE
todoitems_datasync();
Tento trigger můžete nainstalovat buď pomocí migrace, nebo bezprostředně po EnsureCreated()
vytvoření databáze.
Sqlite
Upozorňující
Nepoužívejte SqLite pro produkční služby. SqLite je vhodný pouze pro použití na straně klienta v produkčním prostředí.
SqLite nemá pole data a času, které podporuje přesnost milisekund. Proto není vhodný pro nic kromě testování. Pokud chcete použít SqLite, ujistěte se, že v každém modelu implementujete převaděč hodnot a porovnávač hodnot pro vlastnosti data a času. Nejjednodušší metoda implementace převaděčů hodnot a porovnávačů je v OnModelCreating(ModelBuilder)
metodě vaší DbContext
:
protected override void OnModelCreating(ModelBuilder builder)
{
var timestampProps = builder.Model.GetEntityTypes().SelectMany(t => t.GetProperties())
.Where(p => p.ClrType == typeof(byte[]) && p.ValueGenerated == ValueGenerated.OnAddOrUpdate);
var converter = new ValueConverter<byte[], string>(
v => Encoding.UTF8.GetString(v),
v => Encoding.UTF8.GetBytes(v)
);
foreach (var property in timestampProps)
{
property.SetValueConverter(converter);
property.SetDefaultValueSql("STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')");
}
base.OnModelCreating(builder);
}
Nainstalujte trigger aktualizace při inicializaci databáze:
internal static void InstallUpdateTriggers(DbContext context)
{
foreach (var table in context.Model.GetEntityTypes())
{
var props = table.GetProperties().Where(prop => prop.ClrType == typeof(byte[]) && prop.ValueGenerated == ValueGenerated.OnAddOrUpdate);
foreach (var property in props)
{
var sql = $@"
CREATE TRIGGER s_{table.GetTableName()}_{prop.Name}_UPDATE AFTER UPDATE ON {table.GetTableName()}
BEGIN
UPDATE {table.GetTableName()}
SET {prop.Name} = STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')
WHERE rowid = NEW.rowid;
END
";
context.Database.ExecuteSqlRaw(sql);
}
}
}
Ujistěte se, že InstallUpdateTriggers
metoda je volána pouze jednou během inicializace databáze:
public void InitializeDatabase(DbContext context)
{
bool created = context.Database.EnsureCreated();
if (created && context.Database.IsSqlite())
{
InstallUpdateTriggers(context);
}
context.Database.SaveChanges();
}
LiteDB
LiteDB je bezserverová databáze doručená v jedné malé knihovně DLL napsané ve spravovaném kódu .NET C#. Jedná se o jednoduché a rychlé databázové řešení NoSQL pro samostatné aplikace. Použití LiteDb s trvalým úložištěm na disku:
Microsoft.AspNetCore.Datasync.LiteDb
Nainstalujte balíček z NuGetu.Přidejte jedenton pro :
LiteDatabase
Program.cs
const connectionString = builder.Configuration.GetValue<string>("LiteDb:ConnectionString"); builder.Services.AddSingleton<LiteDatabase>(new LiteDatabase(connectionString));
Odvozujte modely z
LiteDbTableData
:public class TodoItem : LiteDbTableData { public string Title { get; set; } public bool Completed { get; set; } }
Můžete použít libovolný z
BsonMapper
atributů, které jsou dodávány s balíčkem NuGet LiteDb.Vytvořte kontroler pomocí příkazu
LiteDbRepository
:[Route("tables/[controller]")] public class TodoItemController : TableController<TodoItem> { public TodoItemController(LiteDatabase db) : base() { Repository = new LiteDbRepository<TodoItem>(db, "todoitems"); } }
Podpora OpenAPI
Rozhraní API definované kontrolery synchronizace dat můžete publikovat pomocí NSwag nebo Swashbuckle. V obou případech začněte nastavením služby jako obvykle pro vybranou knihovnu.
NSwag
Postupujte podle základníchpokynůch
Přidejte do projektu balíčky pro podporu NSwag. Jsou vyžadovány následující balíčky:
Na začátek
Program.cs
souboru přidejte následující položky:using Microsoft.AspNetCore.Datasync.NSwag;
Přidejte službu pro vygenerování definice OpenAPI do souboru
Program.cs
:builder.Services.AddOpenApiDocument(options => { options.AddDatasyncProcessors(); });
Povolte middleware pro obsluhu vygenerovaného dokumentu JSON a uživatelského rozhraní Swagger, a to také v
Program.cs
:if (app.Environment.IsDevelopment()) { app.UseOpenApi(); app.UseSwaggerUI3(); }
Procházením /swagger
koncového bodu webové služby můžete procházet rozhraní API. Definici OpenAPI je pak možné importovat do jiných služeb (jako je Azure API Management). Další informace o konfiguraci NSwag najdete v tématu Začínáme se službou NSwag a ASP.NET Core.
Swashbuckle
Postupujte podle základních pokynů pro integraci Swashbuckle a pak upravte následujícím způsobem:
Přidejte do projektu balíčky pro podporu Swashbuckle. Jsou vyžadovány následující balíčky:
Přidejte službu pro vygenerování definice OpenAPI do souboru
Program.cs
:builder.Services.AddSwaggerGen(options => { options.AddDatasyncControllers(); }); builder.Services.AddSwaggerGenNewtonsoftSupport();
Poznámka:
Metoda
AddDatasyncControllers()
přebírá volitelnouAssembly
, která odpovídá sestavení, které obsahuje kontrolery tabulky. ParametrAssembly
se vyžaduje jenom v případě, že jsou kontrolery tabulek v jiném projektu, než je služba.Povolte middleware pro obsluhu vygenerovaného dokumentu JSON a uživatelského rozhraní Swagger, a to také v
Program.cs
:if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(options => { options.SwaggerEndpoint("/swagger/v1/swagger.json", "v1"); options.RoutePrefix = string.Empty; }); }
Při této konfiguraci vám procházení kořenového adresáře webové služby umožňuje procházet rozhraní API. Definici OpenAPI je pak možné importovat do jiných služeb (jako je Azure API Management). Další informace o konfiguraci Swashbuckle najdete v tématu Začínáme s Swashbuckle a ASP.NET Core.
Omezení
Edice ASP.NET Core knihoven služeb implementuje pro operaci seznamu OData v4. Pokud server běží v režimu zpětné kompatibility, filtrování podřetězce se nepodporuje.
Váš názor
https://aka.ms/ContentUserFeedback.
Připravujeme: V průběhu roku 2024 budeme postupně vyřazovat problémy z GitHub coby mechanismus zpětné vazby pro obsah a nahrazovat ho novým systémem zpětné vazby. Další informace naleznete v tématu:Odeslat a zobrazit názory pro