Update admin project to use new IAliasServerDbContextFactory (#190)

This commit is contained in:
Leendert de Borst
2024-12-22 00:37:13 +01:00
parent 54d54f28b4
commit 8fbd10caaa
9 changed files with 148 additions and 38 deletions

View File

@@ -56,10 +56,10 @@ public abstract class MainBase : OwningComponentBase
protected AliasServerDbContext DbContext { get; set; } = null!;
/// <summary>
/// Gets or sets the AliasServerDbContextFactory instance.
/// Gets or sets the IAliasServerDbContextFactory instance.
/// </summary>
[Inject]
protected IDbContextFactory<AliasServerDbContext> DbContextFactory { get; set; } = null!;
protected IAliasServerDbContextFactory DbContextFactory { get; set; } = null!;
/// <summary>
/// Gets or sets the GlobalLoadingService in order to manipulate the global loading spinner animation.

View File

@@ -69,7 +69,7 @@ builder.Services.ConfigureApplicationCookie(options =>
options.LoginPath = "/user/login";
});
builder.Services.AddAliasVaultSqliteConfiguration();
builder.Services.AddAliasVaultDatabaseConfiguration(builder.Configuration);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddIdentityCore<AdminUser>(options =>
{
@@ -133,7 +133,7 @@ app.MapRazorComponents<App>()
using (var scope = app.Services.CreateScope())
{
var container = scope.ServiceProvider;
await using var db = await container.GetRequiredService<IDbContextFactory<AliasServerDbContext>>().CreateDbContextAsync();
await using var db = container.GetRequiredService<IAliasServerDbContextFactory>().CreateDbContext();
await db.Database.MigrateAsync();
await StartupTasks.CreateRolesIfNotExist(scope.ServiceProvider);

View File

@@ -1,4 +1,5 @@
{
"DatabaseProvider": "sqlite",
"ConnectionStrings": {
"AliasServerDbContext": "Data Source=../../database/AliasServerDb.sqlite"
},

View File

@@ -18,12 +18,12 @@ using Microsoft.Extensions.Configuration;
/// we have two separate user objects, one for the admin panel and one for the vault. We manually
/// define the Identity tables in the OnModelCreating method.
/// </summary>
public abstract class AliasServerDbContext : WorkerStatusDbContext, IDataProtectionKeyContext
public class AliasServerDbContext : WorkerStatusDbContext, IDataProtectionKeyContext
{
/// <summary>
/// Initializes a new instance of the <see cref="AliasServerDbContext"/> class.
/// </summary>
protected AliasServerDbContext()
public AliasServerDbContext()
{
}
@@ -31,7 +31,7 @@ public abstract class AliasServerDbContext : WorkerStatusDbContext, IDataProtect
/// Initializes a new instance of the <see cref="AliasServerDbContext"/> class.
/// </summary>
/// <param name="options">DbContextOptions.</param>
protected AliasServerDbContext(DbContextOptions<AliasServerDbContext> options)
public AliasServerDbContext(DbContextOptions<AliasServerDbContext> options)
: base(options)
{
}

View File

@@ -7,9 +7,6 @@
namespace AliasServerDb.Configuration;
using System.Data.Common;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
@@ -22,39 +19,29 @@ public static class DatabaseConfiguration
/// Configures SQLite for use with Entity Framework Core.
/// </summary>
/// <param name="services">The IServiceCollection to add the DbContext to.</param>
/// <param name="configuration">The IConfiguration to use for the connection string.</param>
/// <returns>The IServiceCollection for method chaining.</returns>
public static IServiceCollection AddAliasVaultSqliteConfiguration(this IServiceCollection services)
public static IServiceCollection AddAliasVaultDatabaseConfiguration(this IServiceCollection services, IConfiguration configuration)
{
var serviceProvider = services.BuildServiceProvider();
var configuration = serviceProvider.GetRequiredService<IConfiguration>();
var dbProvider = configuration.GetValue<string>("DatabaseProvider")?.ToLower() ?? "sqlite";
var connectionString = configuration.GetConnectionString("AliasServerDbContext");
if (string.IsNullOrEmpty(connectionString))
switch (dbProvider)
{
throw new InvalidOperationException("Connection string 'AliasServerDbContext' not found.");
case "postgresql":
services.AddScoped<IAliasServerDbContextFactory, PostgresqlDbContextFactory>();
break;
case "sqlite":
default:
services.AddScoped<IAliasServerDbContextFactory, SqliteDbContextFactory>();
break;
}
var sqliteConnectionStringBuilder = new SqliteConnectionStringBuilder(connectionString)
services.AddScoped<AliasServerDbContext>(sp =>
{
Cache = SqliteCacheMode.Private,
Mode = SqliteOpenMode.ReadWriteCreate,
};
services.AddDbContextFactory<AliasServerDbContext>(options =>
{
options.UseSqlite(CreateAndConfigureSqliteConnection(sqliteConnectionStringBuilder.ConnectionString), sqliteOptions =>
{
sqliteOptions.CommandTimeout(60);
}).UseLazyLoadingProxies();
var factory = sp.GetRequiredService<IAliasServerDbContextFactory>();
return factory.CreateDbContext();
});
return services;
}
private static SqliteConnection CreateAndConfigureSqliteConnection(string connectionString)
{
var connection = new SqliteConnection(connectionString);
connection.Open();
return connection;
}
}

View File

@@ -0,0 +1,27 @@
//-----------------------------------------------------------------------
// <copyright file="IAliasServerDbContextFactory.cs" company="lanedirt">
// Copyright (c) lanedirt. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasServerDb;
/// <summary>
/// The AliasServerDbContextFactory interface.
/// </summary>
public interface IAliasServerDbContextFactory
{
/// <summary>
/// Creates a new AliasServerDbContext.
/// </summary>
/// <returns>The AliasServerDbContext.</returns>
AliasServerDbContext CreateDbContext();
/// <summary>
/// Creates a new AliasServerDbContext asynchronously.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the AliasServerDbContext.</returns>
Task<AliasServerDbContext> CreateDbContextAsync(CancellationToken cancellationToken = default);
}

View File

@@ -0,0 +1,47 @@
//-----------------------------------------------------------------------
// <copyright file="PostgresqlDbContextFactory.cs" company="lanedirt">
// Copyright (c) lanedirt. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasServerDb;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
/// <summary>
/// The AliasServerDbContextFactory interface.
/// </summary>
public class PostgresqlDbContextFactory : IAliasServerDbContextFactory
{
private readonly IConfiguration _configuration;
/// <summary>
/// Initializes a new instance of the <see cref="PostgresqlDbContextFactory"/> class.
/// </summary>
/// <param name="configuration">The configuration.</param>
public PostgresqlDbContextFactory(IConfiguration configuration)
{
_configuration = configuration;
}
/// <inheritdoc/>
public AliasServerDbContext CreateDbContext()
{
var optionsBuilder = new DbContextOptionsBuilder<AliasServerDbContext>();
var connectionString = _configuration.GetConnectionString("AliasServerDbContext");
optionsBuilder
.UseNpgsql(connectionString, options => options.CommandTimeout(60))
.UseLazyLoadingProxies();
return new AliasServerDbContextPostgresql(optionsBuilder.Options);
}
/// <inheritdoc/>
public Task<AliasServerDbContext> CreateDbContextAsync(CancellationToken cancellationToken = default)
{
return Task.FromResult(CreateDbContext());
}
}

View File

@@ -0,0 +1,48 @@
//-----------------------------------------------------------------------
// <copyright file="SqliteDbContextFactory.cs" company="lanedirt">
// Copyright (c) lanedirt. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasServerDb;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
/// <summary>
/// The AliasServerDbContextFactory interface.
/// </summary>
public class SqliteDbContextFactory : IAliasServerDbContextFactory
{
private readonly IConfiguration _configuration;
/// <summary>
/// Initializes a new instance of the <see cref="SqliteDbContextFactory"/> class.
/// </summary>
/// <param name="configuration">The configuration.</param>
public SqliteDbContextFactory(IConfiguration configuration)
{
_configuration = configuration;
}
/// <inheritdoc/>
public AliasServerDbContext CreateDbContext()
{
var optionsBuilder = new DbContextOptionsBuilder<AliasServerDbContext>();
var connectionString = _configuration.GetConnectionString("AliasServerDbContext") +
";Mode=ReadWriteCreate;Cache=Shared";
optionsBuilder
.UseSqlite(connectionString, options => options.CommandTimeout(60))
.UseLazyLoadingProxies();
return new AliasServerDbContextSqlite(optionsBuilder.Options);
}
/// <inheritdoc/>
public Task<AliasServerDbContext> CreateDbContextAsync(CancellationToken cancellationToken = default)
{
return Task.FromResult(CreateDbContext());
}
}

View File

@@ -20,7 +20,7 @@ using Microsoft.EntityFrameworkCore;
/// Server settings service.
/// </summary>
/// <param name="dbContextFactory">IDbContextFactory instance.</param>
public class ServerSettingsService(IDbContextFactory<AliasServerDbContext> dbContextFactory)
public class ServerSettingsService(IAliasServerDbContextFactory dbContextFactory)
{
private readonly Dictionary<string, string?> _cache = new();
@@ -36,7 +36,7 @@ public class ServerSettingsService(IDbContextFactory<AliasServerDbContext> dbCon
return cachedValue;
}
await using var dbContext = await dbContextFactory.CreateDbContextAsync(CancellationToken.None);
await using var dbContext = dbContextFactory.CreateDbContext();
var setting = await dbContext.ServerSettings.FirstOrDefaultAsync(x => x.Key == key);
_cache[key] = setting?.Value;
@@ -57,7 +57,7 @@ public class ServerSettingsService(IDbContextFactory<AliasServerDbContext> dbCon
return;
}
await using var dbContext = await dbContextFactory.CreateDbContextAsync(CancellationToken.None);
await using var dbContext = dbContextFactory.CreateDbContext();
var setting = await dbContext.ServerSettings.FirstOrDefaultAsync(x => x.Key == key);
var now = DateTime.UtcNow;
@@ -96,7 +96,7 @@ public class ServerSettingsService(IDbContextFactory<AliasServerDbContext> dbCon
/// <returns>The settings.</returns>
public async Task<ServerSettingsModel> GetAllSettingsAsync()
{
await using var dbContext = await dbContextFactory.CreateDbContextAsync(CancellationToken.None);
await using var dbContext = dbContextFactory.CreateDbContext();
var settings = await dbContext.ServerSettings.ToDictionaryAsync(x => x.Key, x => x.Value);
// Create model with defaults