From 41c5a71d85712c8bb7c91ae516c9d0221bce92be Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Mon, 20 Apr 2026 11:57:51 -0700 Subject: [PATCH] YesSql Cleanup --- .../AzureSpeechServiceTextToSpeechClient.cs | 1 + src/Startup/CrestApps.Core.Mvc.Web/Program.cs | 87 +++---------------- .../YesSqlServiceCollectionExtensions.cs | 27 ------ 3 files changed, 14 insertions(+), 101 deletions(-) diff --git a/src/Primitives/CrestApps.Core.AI.OpenAI.Azure/Services/AzureSpeechServiceTextToSpeechClient.cs b/src/Primitives/CrestApps.Core.AI.OpenAI.Azure/Services/AzureSpeechServiceTextToSpeechClient.cs index 604ea7ce..581be7bc 100644 --- a/src/Primitives/CrestApps.Core.AI.OpenAI.Azure/Services/AzureSpeechServiceTextToSpeechClient.cs +++ b/src/Primitives/CrestApps.Core.AI.OpenAI.Azure/Services/AzureSpeechServiceTextToSpeechClient.cs @@ -241,6 +241,7 @@ public async Task GetVoicesAsync( return []; } + /// public object GetService(Type serviceType, object serviceKey = null) { diff --git a/src/Startup/CrestApps.Core.Mvc.Web/Program.cs b/src/Startup/CrestApps.Core.Mvc.Web/Program.cs index 7d2ea0a8..2e841867 100644 --- a/src/Startup/CrestApps.Core.Mvc.Web/Program.cs +++ b/src/Startup/CrestApps.Core.Mvc.Web/Program.cs @@ -74,42 +74,6 @@ // Early startup marker — writes immediately to confirm the process launched. var crashLogDir = Path.Combine(builder.Environment.ContentRootPath, "App_Data", "logs"); Directory.CreateDirectory(crashLogDir); -File.WriteAllText( - Path.Combine(crashLogDir, "startup-marker.txt"), - $"Process started at {DateTime.UtcNow:O}, PID={Environment.ProcessId}{Environment.NewLine}"); - -AppDomain.CurrentDomain.UnhandledException += (_, e) => -{ - var message = $"[{DateTime.UtcNow:O}] Unhandled exception (IsTerminating={e.IsTerminating}):{Environment.NewLine}{e.ExceptionObject}{Environment.NewLine}"; - - try - { - File.AppendAllText(Path.Combine(crashLogDir, "crash.log"), message); - } - catch - { - // Best-effort — the process is already dying. - } - - Console.Error.Write(message); -}; - -TaskScheduler.UnobservedTaskException += (_, e) => -{ - var message = $"[{DateTime.UtcNow:O}] Unobserved task exception:{Environment.NewLine}{e.Exception}{Environment.NewLine}"; - - try - { - File.AppendAllText(Path.Combine(crashLogDir, "crash.log"), message); - } - catch - { - // Best-effort. - } - - Console.Error.Write(message); - e.SetObserved(); -}; // Prevent background/hosted-service exceptions from tearing down the host. // The default BackgroundServiceExceptionBehavior.StopHost silently kills the @@ -120,6 +84,7 @@ { options.BackgroundServiceExceptionBehavior = BackgroundServiceExceptionBehavior.Ignore; }); + // ============================================================================= // 2. LOGGING // ============================================================================= @@ -131,6 +96,7 @@ builder.WebHost.UseNLog(); var appDataPath = Path.Combine(builder.Environment.ContentRootPath, "App_Data"); Directory.CreateDirectory(appDataPath); + // ============================================================================= // 3. APPLICATION CONFIGURATION // ============================================================================= @@ -164,6 +130,7 @@ builder.Services.AddSingleton, SiteSettingsConfigureAIDataSourceOptions>(); builder.Services.AddSingleton, SiteSettingsConfigureChatInteractionMemoryOptions>(); builder.Services.AddSingleton, SiteSettingsConfigureDefaultDeploymentOptions>(); + // ============================================================================= // 4. ASP.NET CORE MVC SETUP // ============================================================================= @@ -173,7 +140,9 @@ builder.Services.AddLocalization(); builder.Services.AddControllersWithViews() .AddCrestAppsStoreCommitterFilter(); + builder.Services.AddHttpContextAccessor(); + // ============================================================================= // 5. AUTHENTICATION & AUTHORIZATION // ============================================================================= @@ -185,8 +154,10 @@ options.LoginPath = "/Account/Login"; options.AccessDeniedPath = "/Account/AccessDenied"; }); + builder.Services.AddAuthorizationBuilder() .AddPolicy("Admin", policy => policy.RequireRole("Administrator")); + // ============================================================================= // 6. CRESTAPPS FOUNDATION + AI SERVICES // ============================================================================= @@ -367,24 +338,11 @@ var app = builder.Build(); -try -{ - // YesSql schema initialization — creates tables on first run. - await app.Services.InitializeYesSqlSchemaAsync(); - - // Seed sample articles on first run. - await app.Services.SeedArticlesAsync(); -} -catch (Exception ex) -{ - var msg = $"[{DateTime.UtcNow:O}] Startup initialization failed:{Environment.NewLine}{ex}{Environment.NewLine}"; +// YesSql schema initialization — creates tables on first run. +await app.Services.InitializeYesSqlSchemaAsync(); - try { File.AppendAllText(Path.Combine(crashLogDir, "crash.log"), msg); } catch { } - - Console.Error.Write(msg); - - throw; -} +// Seed sample articles on first run. +await app.Services.SeedArticlesAsync(); // ============================================================================= // 14. MIDDLEWARE PIPELINE @@ -440,6 +398,7 @@ await next(); }); }); + app.MapHub("/hubs/ai-chat"); app.MapHub("/hubs/chat-interaction"); app.MapMcp("mcp"); @@ -453,24 +412,4 @@ app.MapControllerRoute(name: "areas", pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}"); app.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); -try -{ - await app.RunAsync(); -} -catch (Exception ex) -{ - var crashMessage = $"[{DateTime.UtcNow:O}] Host terminated unexpectedly:{Environment.NewLine}{ex}{Environment.NewLine}"; - - try - { - File.AppendAllText(Path.Combine(crashLogDir, "crash.log"), crashMessage); - } - catch - { - // Best-effort. - } - - Console.Error.Write(crashMessage); - - throw; -} +await app.RunAsync(); diff --git a/src/Startup/CrestApps.Core.Mvc.Web/Services/YesSqlServiceCollectionExtensions.cs b/src/Startup/CrestApps.Core.Mvc.Web/Services/YesSqlServiceCollectionExtensions.cs index cc1f715c..85287256 100644 --- a/src/Startup/CrestApps.Core.Mvc.Web/Services/YesSqlServiceCollectionExtensions.cs +++ b/src/Startup/CrestApps.Core.Mvc.Web/Services/YesSqlServiceCollectionExtensions.cs @@ -38,8 +38,6 @@ namespace CrestApps.Core.Mvc.Web.Services; internal static class YesSqlServiceCollectionExtensions { - private static readonly (string LegacyValue, string CurrentValue)[] _legacyDocumentTypeReplacements = [("CrestApps.AI.", "CrestApps.Core.AI."), ("CrestApps.Infrastructure.", "CrestApps.Core.Infrastructure."), ("CrestApps.Mvc.Web", "CrestApps.Core.Mvc.Web"),]; - /// /// Registers YesSql with SQLite, all index providers, and the catalog/manager /// services that the MVC sample application needs. Call this from Program.cs to @@ -137,7 +135,6 @@ public static async Task InitializeYesSqlSchemaAsync(this IServiceProvider servi await ConfigureSqliteConnectionAsync(connection); await using var transaction = await connection.BeginTransactionAsync(); var schemaBuilder = new SchemaBuilder(store.Configuration, transaction); - await NormalizeLegacyDocumentTypeNamesAsync(store, connection, transaction, logger); await TryCreateTableAsync(() => schemaBuilder.CreateAIProfileIndexSchemaAsync(storeOptions)); await TryCreateTableAsync(() => schemaBuilder.CreateAIProviderConnectionIndexSchemaAsync(storeOptions)); await TryCreateTableAsync(() => schemaBuilder.CreateA2AConnectionIndexSchemaAsync(storeOptions)); @@ -176,30 +173,6 @@ private static async Task ConfigureSqliteConnectionAsync(DbConnection connection await command.ExecuteNonQueryAsync(); } - private static async Task NormalizeLegacyDocumentTypeNamesAsync(IStore store, DbConnection connection, DbTransaction transaction, ILogger logger) - { - var dialect = store.Configuration.SqlDialect; - var documentTableName = store.Configuration.TableNameConvention.GetDocumentTable(string.Empty); - var table = $"{store.Configuration.TablePrefix}{documentTableName}"; - var quotedTableName = dialect.QuoteForTableName(table, store.Configuration.Schema); - var quotedTypeColumnName = dialect.QuoteForColumnName(nameof(Document.Type)); - foreach (var (legacyValue, currentValue) in _legacyDocumentTypeReplacements) - { - await using var command = connection.CreateCommand(); - command.Transaction = transaction; - command.CommandText = $""" - UPDATE {quotedTableName} - SET {quotedTypeColumnName} = REPLACE({quotedTypeColumnName}, '{legacyValue}', '{currentValue}') - WHERE {quotedTypeColumnName} LIKE '%{legacyValue}%' - """; - var updated = await command.ExecuteNonQueryAsync(); - if (updated > 0 && logger.IsEnabled(LogLevel.Information)) - { - logger.LogInformation("Updated {Count} stored YesSql document type names in {TableName} from '{LegacyValue}' to '{CurrentValue}'.", updated, table, legacyValue, currentValue); - } - } - } - private static async Task EnsureAIDocumentIndexExtensionColumnAsync(IStore store, DbConnection connection, DbTransaction transaction, SchemaBuilder schemaBuilder, YesSqlStoreOptions storeOptions, ILogger logger) { var tableName = await FindIndexTableNameAsync(connection, transaction, store.Configuration.TablePrefix, nameof(AIDocumentIndex));