From b0227ed6e5801f6b77a7e409439bd8afeda3e60e Mon Sep 17 00:00:00 2001 From: Maddy Montaquila Date: Fri, 1 Aug 2025 15:21:30 -0400 Subject: [PATCH 01/12] HELP Co-authored-by: Tommaso Stocchi Co-authored-by: Damian Edwards Co-authored-by: Safia Abdalla --- .aspire/settings.json | 3 + Nuget.config | 3 +- src/.editorconfig | 6 +- src/Azure.DataApiBuilder.sln | 8 +- src/Directory.Packages.props | 3 + src/Service/Properties/launchSettings.json | 26 +- src/apphost/AppHost.cs | 53 ++++ src/apphost/Properties/launchSettings.json | 29 +++ src/apphost/apphost.csproj | 23 ++ src/apphost/apphost.csproj.Backup.tmp | 21 ++ src/apphost/appsettings.json | 9 + src/apphost/init-scripts/create-database.sql | 238 +++++++++++++++++ .../init-scripts/pg/create-database-pg.sql | 243 ++++++++++++++++++ 13 files changed, 639 insertions(+), 26 deletions(-) create mode 100644 .aspire/settings.json create mode 100644 src/apphost/AppHost.cs create mode 100644 src/apphost/Properties/launchSettings.json create mode 100644 src/apphost/apphost.csproj create mode 100644 src/apphost/apphost.csproj.Backup.tmp create mode 100644 src/apphost/appsettings.json create mode 100644 src/apphost/init-scripts/create-database.sql create mode 100644 src/apphost/init-scripts/pg/create-database-pg.sql diff --git a/.aspire/settings.json b/.aspire/settings.json new file mode 100644 index 0000000000..71d0d3f204 --- /dev/null +++ b/.aspire/settings.json @@ -0,0 +1,3 @@ +{ + "appHostPath": "../src/apphost/apphost.csproj" +} \ No newline at end of file diff --git a/Nuget.config b/Nuget.config index 704c9d13ba..fd8d459f1a 100644 --- a/Nuget.config +++ b/Nuget.config @@ -2,7 +2,8 @@ - + + diff --git a/src/.editorconfig b/src/.editorconfig index 5639a063ae..6367bdcb3c 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -75,9 +75,9 @@ dotnet_style_allow_statement_immediately_after_block_experimental = false:error #### C# Coding Conventions #### # var preferences -csharp_style_var_elsewhere = false:error -csharp_style_var_for_built_in_types = false:error -csharp_style_var_when_type_is_apparent = false:error +# csharp_style_var_elsewhere = false:error +# csharp_style_var_for_built_in_types = false:error +# csharp_style_var_when_type_is_apparent = false:error # Modifier preferences csharp_prefer_static_local_function = true:suggestion diff --git a/src/Azure.DataApiBuilder.sln b/src/Azure.DataApiBuilder.sln index e7f61fa3ed..bdbfe3a092 100644 --- a/src/Azure.DataApiBuilder.sln +++ b/src/Azure.DataApiBuilder.sln @@ -1,4 +1,4 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.3.32405.409 MinimumVisualStudioVersion = 10.0.40219.1 @@ -31,6 +31,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.DataApiBuilder.Core", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.DataApiBuilder.Product", "Product\Azure.DataApiBuilder.Product.csproj", "{E3D2076C-EE49-43A0-8F92-5FC41EC99DA7}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "apphost", "apphost\apphost.csproj", "{87B53030-EB52-4EB1-870D-72540DA4724E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -73,6 +75,10 @@ Global {E3D2076C-EE49-43A0-8F92-5FC41EC99DA7}.Debug|Any CPU.Build.0 = Debug|Any CPU {E3D2076C-EE49-43A0-8F92-5FC41EC99DA7}.Release|Any CPU.ActiveCfg = Release|Any CPU {E3D2076C-EE49-43A0-8F92-5FC41EC99DA7}.Release|Any CPU.Build.0 = Release|Any CPU + {87B53030-EB52-4EB1-870D-72540DA4724E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {87B53030-EB52-4EB1-870D-72540DA4724E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {87B53030-EB52-4EB1-870D-72540DA4724E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {87B53030-EB52-4EB1-870D-72540DA4724E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index ee79b16b00..66f085e114 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -3,6 +3,9 @@ true + + + diff --git a/src/Service/Properties/launchSettings.json b/src/Service/Properties/launchSettings.json index acd7ab6646..becf6cd238 100644 --- a/src/Service/Properties/launchSettings.json +++ b/src/Service/Properties/launchSettings.json @@ -1,22 +1,6 @@ { - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:35704", - "sslPort": 44353 - } - }, "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "launchUrl": "graphql", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, "Azure.DataApiBuilder.Service": { "commandName": "Project", "launchBrowser": true, @@ -24,7 +8,7 @@ "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "MsSql" }, - "dotnetRunMessages": "true", + "dotnetRunMessages": true, "applicationUrl": "https://localhost:5001;http://localhost:5000" }, "Development": { @@ -34,7 +18,7 @@ "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, - "dotnetRunMessages": "true", + "dotnetRunMessages": true, "applicationUrl": "https://localhost:5001;http://localhost:5000" }, "PostgreSql": { @@ -44,7 +28,7 @@ "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "PostgreSql" }, - "dotnetRunMessages": "true", + "dotnetRunMessages": true, "applicationUrl": "https://localhost:5001;http://localhost:5000" }, "MsSql": { @@ -54,7 +38,7 @@ "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "MsSql" }, - "dotnetRunMessages": "true", + "dotnetRunMessages": true, "applicationUrl": "https://localhost:5001;http://localhost:5000" }, "MySql": { @@ -64,7 +48,7 @@ "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "MySql" }, - "dotnetRunMessages": "true", + "dotnetRunMessages": true, "applicationUrl": "https://localhost:5001;http://localhost:5000" }, "CosmosDb_NoSql": { diff --git a/src/apphost/AppHost.cs b/src/apphost/AppHost.cs new file mode 100644 index 0000000000..7ce1986c46 --- /dev/null +++ b/src/apphost/AppHost.cs @@ -0,0 +1,53 @@ +var builder = DistributedApplication.CreateBuilder(args); + +var sqlDbContainer = builder.AddSqlServer("sqlserver") + .WithDataVolume() + .WithLifetime(ContainerLifetime.Persistent); + +var sqlScript = File.ReadAllText("./init-scripts/create-database.sql"); + +var msSql = sqlDbContainer.AddDatabase("msSqlDb", "Trek") + .WithCreationScript(sqlScript); + +var postgresDB = builder.AddPostgres("postgres") + .WithDataVolume() + .WithPgAdmin() + .WithInitFiles("./init-scripts/pg") + .WithLifetime(ContainerLifetime.Persistent) + .AddDatabase("pgSqlDb", "Trek"); + +builder.AddProject("mssql-service", "Development") + .WithArgs("-f", "net8.0") + .WithEndpoint(endpointName: "https", (e) => + { + e.Port = 6834; + }) + .WithEnvironment("ConnectionStrings__Trek", msSql) + .WithEnvironment("db-type", "mssql") + .WithUrls((e) => + { + e.Urls.Clear(); + e.Urls.Add(new() { Url = "/swagger", DisplayText = "🔒Swagger", Endpoint = e.GetEndpoint("https") }); + e.Urls.Add(new() { Url = "/graphql", DisplayText = "🔒GraphQL", Endpoint = e.GetEndpoint("https") }); + }) + .WithHttpHealthCheck("/health") + .WaitFor(msSql); + +builder.AddProject("pg-service", "Development") + .WithArgs("-f", "net8.0") + .WithEndpoint(endpointName: "https", (e) => + { + e.Port = 7834; + }) + .WithEnvironment("ConnectionStrings__Trek", postgresDB) + .WithEnvironment("db-type", "postgresql") + .WithUrls((e) => + { + e.Urls.Clear(); + e.Urls.Add(new() { Url = "/swagger", DisplayText = "🔒Swagger", Endpoint = e.GetEndpoint("https") }); + e.Urls.Add(new() { Url = "/graphql", DisplayText = "🔒GraphQL", Endpoint = e.GetEndpoint("https") }); + }) + .WithHttpHealthCheck("/health") + .WaitFor(postgresDB); + +builder.Build().Run(); diff --git a/src/apphost/Properties/launchSettings.json b/src/apphost/Properties/launchSettings.json new file mode 100644 index 0000000000..2a5a9a359f --- /dev/null +++ b/src/apphost/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:17047;http://localhost:15161", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21213", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22145" + } + }, + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:15161", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19015", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20166" + } + } + } +} diff --git a/src/apphost/apphost.csproj b/src/apphost/apphost.csproj new file mode 100644 index 0000000000..6bafa2aa61 --- /dev/null +++ b/src/apphost/apphost.csproj @@ -0,0 +1,23 @@ + + + + + + Exe + net8.0 + enable + enable + f08719fd-267f-459e-9980-77b1c52c8755 + + + + + + + + + + + + + diff --git a/src/apphost/apphost.csproj.Backup.tmp b/src/apphost/apphost.csproj.Backup.tmp new file mode 100644 index 0000000000..088efcfc83 --- /dev/null +++ b/src/apphost/apphost.csproj.Backup.tmp @@ -0,0 +1,21 @@ + + + + + + Exe + net8.0 + enable + enable + f08719fd-267f-459e-9980-77b1c52c8755 + + + + + + + + + + + diff --git a/src/apphost/appsettings.json b/src/apphost/appsettings.json new file mode 100644 index 0000000000..31c092aa45 --- /dev/null +++ b/src/apphost/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning", + "Aspire.Hosting.Dcp": "Warning" + } + } +} diff --git a/src/apphost/init-scripts/create-database.sql b/src/apphost/init-scripts/create-database.sql new file mode 100644 index 0000000000..cef265a293 --- /dev/null +++ b/src/apphost/init-scripts/create-database.sql @@ -0,0 +1,238 @@ + +USE [master] +GO + +CREATE DATABASE [Trek] +GO + +USE [Trek] +GO + +-- Drop tables in reverse order of creation due to foreign key dependencies +DROP TABLE IF EXISTS Character_Species; +DROP TABLE IF EXISTS Series_Character; +DROP TABLE IF EXISTS Character; +DROP TABLE IF EXISTS Species; +DROP TABLE IF EXISTS Actor; +DROP TABLE IF EXISTS Series; + +-- create tables +CREATE TABLE Series ( + Id INT PRIMARY KEY, + Name NVARCHAR(255) NOT NULL +); + +CREATE TABLE Actor ( + Id INT PRIMARY KEY, + Name NVARCHAR(255) NOT NULL, + [BirthYear] INT NOT NULL +); + +CREATE TABLE Species ( + Id INT PRIMARY KEY, + Name NVARCHAR(255) NOT NULL +); + +CREATE TABLE Character ( + Id INT PRIMARY KEY, + Name NVARCHAR(255) NOT NULL, + ActorId INT NOT NULL, + Stardate DECIMAL(10, 2), + FOREIGN KEY (ActorId) REFERENCES Actor(Id) +); + +CREATE TABLE Series_Character ( + SeriesId INT, + CharacterId INT, + Role VARCHAR(500), + FOREIGN KEY (SeriesId) REFERENCES Series(Id), + FOREIGN KEY (CharacterId) REFERENCES Character(Id), + PRIMARY KEY (SeriesId, CharacterId) +); + +CREATE TABLE Character_Species ( + CharacterId INT, + SpeciesId INT, + FOREIGN KEY (CharacterId) REFERENCES Character(Id), + FOREIGN KEY (SpeciesId) REFERENCES Species(Id), + PRIMARY KEY (CharacterId, SpeciesId) +); + +-- create data +INSERT INTO Series (Id, Name) VALUES + (1, 'Star Trek'), + (2, 'Star Trek: The Next Generation'), + (3, 'Star Trek: Voyager'), + (4, 'Star Trek: Deep Space Nine'), + (5, 'Star Trek: Enterprise'); + +INSERT INTO Species (Id, Name) VALUES + (1, 'Human'), + (2, 'Vulcan'), + (3, 'Android'), + (4, 'Klingon'), + (5, 'Betazoid'), + (6, 'Hologram'), + (7, 'Bajoran'), + (8, 'Changeling'), + (9, 'Trill'), + (10, 'Ferengi'), + (11, 'Denobulan'), + (12, 'Borg'); + +INSERT INTO Actor (Id, Name, [BirthYear]) VALUES + (1, 'William Shatner', 1931), + (2, 'Leonard Nimoy', 1931), + (3, 'DeForest Kelley', 1920), + (4, 'James Doohan', 1920), + (5, 'Nichelle Nichols', 1932), + (6, 'George Takei', 1937), + (7, 'Walter Koenig', 1936), + (8, 'Patrick Stewart', 1940), + (9, 'Jonathan Frakes', 1952), + (10, 'Brent Spiner', 1949), + (11, 'Michael Dorn', 1952), + (12, 'Gates McFadden', 1949), + (13, 'Marina Sirtis', 1955), + (14, 'LeVar Burton', 1957), + (15, 'Kate Mulgrew', 1955), + (16, 'Robert Beltran', 1953), + (17, 'Tim Russ', 1956), + (18, 'Roxann Dawson', 1958), + (19, 'Robert Duncan McNeill', 1964), + (20, 'Garrett Wang', 1968), + (21, 'Robert Picardo', 1953), + (22, 'Jeri Ryan', 1968), + (23, 'Avery Brooks', 1948), + (24, 'Nana Visitor', 1957), + (25, 'Rene Auberjonois', 1940), + (26, 'Terry Farrell', 1963), + (27, 'Alexander Siddig', 1965), + (28, 'Armin Shimerman', 1949), + (29, 'Cirroc Lofton', 1978), + (30, 'Scott Bakula', 1954), + (31, 'Jolene Blalock', 1975), + (32, 'John Billingsley', 1960), + (33, 'Connor Trinneer', 1969), + (34, 'Dominic Keating', 1962), + (35, 'Linda Park', 1978), + (36, 'Anthony Montgomery', 1971); + +INSERT INTO Character (Id, Name, ActorId, Stardate) VALUES + (1, 'James T. Kirk', 1, 2233.04), + (2, 'Spock', 2, 2230.06), + (3, 'Leonard McCoy', 3, 2227.00), + (4, 'Montgomery Scott', 4, 2222.00), + (5, 'Uhura', 5, 2233.00), + (6, 'Hikaru Sulu', 6, 2237.00), + (7, 'Pavel Chekov', 7, 2245.00), + (8, 'Jean-Luc Picard', 8, 2305.07), + (9, 'William Riker', 9, 2335.08), + (10, 'Data', 10, 2336.00), + (11, 'Worf', 11, 2340.00), + (12, 'Beverly Crusher', 12, 2324.00), + (13, 'Deanna Troi', 13, 2336.00), + (14, 'Geordi La Forge', 14, 2335.02), + (15, 'Kathryn Janeway', 15, 2336.05), + (16, 'Chakotay', 16, 2329.00), + (17, 'Tuvok', 17, 2264.00), + (18, 'B''Elanna Torres', 18, 2349.00), + (19, 'Tom Paris', 19, 2346.00), + (20, 'Harry Kim', 20, 2349.00), + (21, 'The Doctor', 21, 2371.00), -- Stardate of activation + (22, 'Seven of Nine', 22, 2348.00), + (23, 'Benjamin Sisko', 23, 2332.00), + (24, 'Kira Nerys', 24, 2343.00), + (25, 'Odo', 25, 2337.00), -- Approximate stardate of discovery + (27, 'Jadzia Dax', 26, 2341.00), + (28, 'Julian Bashir', 27, 2341.00), + (29, 'Quark', 28, 2333.00), + (30, 'Jake Sisko', 29, 2355.00), + (31, 'Jonathan Archer', 30, 2112.00), + (32, 'T''Pol', 31, 2088.00), + (33, 'Phlox', 32, 2102.00), + (34, 'Charles "Trip" Tucker III', 33, 2121.00), + (35, 'Malcolm Reed', 34, 2117.00), + (36, 'Hoshi Sato', 35, 2129.00), + (37, 'Travis Mayweather', 36, 2126.00); + +INSERT INTO Series_Character (SeriesId, CharacterId, Role) VALUES + (1, 1, 'Captain'), -- James T. Kirk in Star Trek + (1, 2, 'Science Officer'), -- Spock in Star Trek + (1, 3, 'Doctor'), -- Leonard McCoy in Star Trek + (1, 4, 'Engineer'), -- Montgomery Scott in Star Trek + (1, 5, 'Communications Officer'), -- Uhura in Star Trek + (1, 6, 'Helmsman'), -- Hikaru Sulu in Star Trek + (1, 7, 'Navigator'), -- Pavel Chekov in Star Trek + (2, 8, 'Captain'), -- Jean-Luc Picard in Star Trek: The Next Generation + (2, 9, 'First Officer'), -- William Riker in Star Trek: The Next Generation + (2, 10, 'Operations Officer'),-- Data in Star Trek: The Next Generation + (2, 11, 'Security Officer'),-- Worf in Star Trek: The Next Generation + (2, 12, 'Doctor'),-- Beverly Crusher in Star Trek: The Next Generation + (2, 13, 'Counselor'),-- Deanna Troi in Star Trek: The Next Generation + (2, 14, 'Engineer'),-- Geordi La Forge in Star Trek: The Next Generation + (3, 15, 'Captain'),-- Kathryn Janeway in Star Trek: Voyager + (3, 16, 'First Officer'),-- Chakotay in Star Trek: Voyager + (3, 17, 'Tactical Officer'),-- Tuvok in Star Trek: Voyager + (3, 18, 'Engineer'),-- B'Elanna Torres in Star Trek: Voyager + (3, 19, 'Helmsman'),-- Tom Paris in Star Trek: Voyager + (3, 20, 'Operations Officer'),-- Harry Kim in Star Trek: Voyager + (3, 21, 'Doctor'),-- The Doctor in Star Trek: Voyager + (3, 22, 'Astrometrics Officer'),-- Seven of Nine in Star Trek: Voyager + (4, 23, 'Commanding Officer'),-- Benjamin Sisko in Star Trek: Deep Space Nine + (4, 24, 'First Officer'),-- Kira Nerys in Star Trek: Deep Space Nine + (4, 25, 'Security Officer'),-- Odo in Star Trek: Deep Space Nine + (4, 11, 'Strategic Operations Officer'),-- Worf in Star Trek: Deep Space Nine + (4, 27, 'Science Officer'),-- Jadzia Dax in Star Trek: Deep Space Nine + (4, 28, 'Doctor'),-- Julian Bashir in Star Trek: Deep Space Nine + (4, 29, 'Bar Owner'),-- Quark in Star Trek: Deep Space Nine + (4, 30, 'Civilian'),-- Jake Sisko in Star Trek: Deep Space Nine + (5, 31, 'Captain'),-- Jonathan Archer in Star Trek: Enterprise + (5, 32, 'Science Officer'),-- T'Pol in Star Trek: Enterprise + (5, 33, 'Doctor'),-- Phlox in Star Trek: Enterprise + (5, 34, 'Chief Engineer'),-- Charles "Trip" Tucker III in Star Trek: Enterprise + (5, 35, 'Armory Officer'),-- Malcolm Reed in Star Trek: Enterprise + (5, 36, 'Communications Officer'),-- Hoshi Sato in Star Trek: Enterprise + (5, 37, 'Helmsman');-- Travis Mayweather in Star Trek: Enterprise + +INSERT INTO Character_Species (CharacterId, SpeciesId) VALUES + (1, 1), -- James T. Kirk is Human + (2, 2), -- Spock is Vulcan + (2, 1), -- Spock is also Human + (3, 1), -- Leonard McCoy is Human + (4, 1), -- Montgomery Scott is Human + (5, 1), -- Uhura is Human + (6, 1), -- Hikaru Sulu is Human + (7, 1), -- Pavel Chekov is Human + (8, 1), -- Jean-Luc Picard is Human + (9, 1), -- William Riker is Human + (10, 3), -- Data is Android + (11, 4), -- Worf is Klingon + (12, 1), -- Beverly Crusher is Human + (13, 1), -- Deanna Troi is Human + (13, 5), -- Deanna Troi is also Betazoid + (14, 1), -- Geordi La Forge is Human + (15, 1), -- Kathryn Janeway is Human + (16, 1), -- Chakotay is Human + (17, 2), -- Tuvok is Vulcan + (18, 1), -- B'Elanna Torres is Human + (18, 4), -- B'Elanna Torres is also Klingon + (19, 1), -- Tom Paris is Human + (20, 1), -- Harry Kim is Human + (21, 6), -- The Doctor is a Hologram + (22, 1), -- Seven of Nine is Human + (22, 12),-- Seven of Nine is also Borg + (23, 1), -- Benjamin Sisko is Human + (24, 7), -- Kira Nerys is Bajoran + (25, 8), -- Odo is Changeling + (27, 9), -- Jadzia Dax is Trill + (28, 1), -- Julian Bashir is Human + (29, 10),-- Quark is Ferengi + (30, 1), -- Jake Sisko is Human + (31, 1), -- Jonathan Archer is Human + (32, 2), -- T'Pol is Vulcan + (33, 11),-- Phlox is Denobulan + (34, 1), -- Charles "Trip" Tucker III is Human + (35, 1), -- Malcolm Reed is Human + (36, 1), -- Hoshi Sato is Human + (37, 1); -- Travis Mayweather is Human \ No newline at end of file diff --git a/src/apphost/init-scripts/pg/create-database-pg.sql b/src/apphost/init-scripts/pg/create-database-pg.sql new file mode 100644 index 0000000000..3b063e9dbf --- /dev/null +++ b/src/apphost/init-scripts/pg/create-database-pg.sql @@ -0,0 +1,243 @@ +-- create-database-pg.sql +-- PostgreSQL version of create-database.sql + +-- Create database (run this as a superuser, outside the target database) +-- Uncomment and edit the database name as needed +-- CREATE DATABASE "Trek" +-- WITH +-- OWNER = trek_user +-- ENCODING = 'UTF8' +-- LC_COLLATE = 'en_US.utf8' +-- LC_CTYPE = 'en_US.utf8' +-- TEMPLATE = template0; + +-- Connect to the target database before running the rest of the script + +-- Drop tables in reverse order of creation due to foreign key dependencies +DROP TABLE IF EXISTS Character_Species; +DROP TABLE IF EXISTS Series_Character; +DROP TABLE IF EXISTS "Character"; +DROP TABLE IF EXISTS Species; +DROP TABLE IF EXISTS Actor; +DROP TABLE IF EXISTS Series; + +-- create tables +CREATE TABLE Series ( + Id INTEGER PRIMARY KEY, + Name VARCHAR(255) NOT NULL +); + +CREATE TABLE Actor ( + Id INTEGER PRIMARY KEY, + Name VARCHAR(255) NOT NULL, + "BirthYear" INTEGER NOT NULL +); + +CREATE TABLE Species ( + Id INTEGER PRIMARY KEY, + Name VARCHAR(255) NOT NULL +); + +CREATE TABLE "Character" ( + Id INTEGER PRIMARY KEY, + Name VARCHAR(255) NOT NULL, + ActorId INTEGER NOT NULL, + Stardate DECIMAL(10, 2), + FOREIGN KEY (ActorId) REFERENCES Actor(Id) +); + +CREATE TABLE Series_Character ( + SeriesId INTEGER, + CharacterId INTEGER, + Role VARCHAR(500), + FOREIGN KEY (SeriesId) REFERENCES Series(Id), + FOREIGN KEY (CharacterId) REFERENCES "Character"(Id), + PRIMARY KEY (SeriesId, CharacterId) +); + +CREATE TABLE Character_Species ( + CharacterId INTEGER, + SpeciesId INTEGER, + FOREIGN KEY (CharacterId) REFERENCES "Character"(Id), + FOREIGN KEY (SpeciesId) REFERENCES Species(Id), + PRIMARY KEY (CharacterId, SpeciesId) +); + +-- create data +INSERT INTO Series (Id, Name) VALUES + (1, 'Star Trek'), + (2, 'Star Trek: The Next Generation'), + (3, 'Star Trek: Voyager'), + (4, 'Star Trek: Deep Space Nine'), + (5, 'Star Trek: Enterprise'); + +INSERT INTO Species (Id, Name) VALUES + (1, 'Human'), + (2, 'Vulcan'), + (3, 'Android'), + (4, 'Klingon'), + (5, 'Betazoid'), + (6, 'Hologram'), + (7, 'Bajoran'), + (8, 'Changeling'), + (9, 'Trill'), + (10, 'Ferengi'), + (11, 'Denobulan'), + (12, 'Borg'); + +INSERT INTO Actor (Id, Name, "BirthYear") VALUES + (1, 'William Shatner', 1931), + (2, 'Leonard Nimoy', 1931), + (3, 'DeForest Kelley', 1920), + (4, 'James Doohan', 1920), + (5, 'Nichelle Nichols', 1932), + (6, 'George Takei', 1937), + (7, 'Walter Koenig', 1936), + (8, 'Patrick Stewart', 1940), + (9, 'Jonathan Frakes', 1952), + (10, 'Brent Spiner', 1949), + (11, 'Michael Dorn', 1952), + (12, 'Gates McFadden', 1949), + (13, 'Marina Sirtis', 1955), + (14, 'LeVar Burton', 1957), + (15, 'Kate Mulgrew', 1955), + (16, 'Robert Beltran', 1953), + (17, 'Tim Russ', 1956), + (18, 'Roxann Dawson', 1958), + (19, 'Robert Duncan McNeill', 1964), + (20, 'Garrett Wang', 1968), + (21, 'Robert Picardo', 1953), + (22, 'Jeri Ryan', 1968), + (23, 'Avery Brooks', 1948), + (24, 'Nana Visitor', 1957), + (25, 'Rene Auberjonois', 1940), + (26, 'Terry Farrell', 1963), + (27, 'Alexander Siddig', 1965), + (28, 'Armin Shimerman', 1949), + (29, 'Cirroc Lofton', 1978), + (30, 'Scott Bakula', 1954), + (31, 'Jolene Blalock', 1975), + (32, 'John Billingsley', 1960), + (33, 'Connor Trinneer', 1969), + (34, 'Dominic Keating', 1962), + (35, 'Linda Park', 1978), + (36, 'Anthony Montgomery', 1971); + +INSERT INTO "Character" (Id, Name, ActorId, Stardate) VALUES + (1, 'James T. Kirk', 1, 2233.04), + (2, 'Spock', 2, 2230.06), + (3, 'Leonard McCoy', 3, 2227.00), + (4, 'Montgomery Scott', 4, 2222.00), + (5, 'Uhura', 5, 2233.00), + (6, 'Hikaru Sulu', 6, 2237.00), + (7, 'Pavel Chekov', 7, 2245.00), + (8, 'Jean-Luc Picard', 8, 2305.07), + (9, 'William Riker', 9, 2335.08), + (10, 'Data', 10, 2336.00), + (11, 'Worf', 11, 2340.00), + (12, 'Beverly Crusher', 12, 2324.00), + (13, 'Deanna Troi', 13, 2336.00), + (14, 'Geordi La Forge', 14, 2335.02), + (15, 'Kathryn Janeway', 15, 2336.05), + (16, 'Chakotay', 16, 2329.00), + (17, 'Tuvok', 17, 2264.00), + (18, 'B''Elanna Torres', 18, 2349.00), + (19, 'Tom Paris', 19, 2346.00), + (20, 'Harry Kim', 20, 2349.00), + (21, 'The Doctor', 21, 2371.00), -- Stardate of activation + (22, 'Seven of Nine', 22, 2348.00), + (23, 'Benjamin Sisko', 23, 2332.00), + (24, 'Kira Nerys', 24, 2343.00), + (25, 'Odo', 25, 2337.00), -- Approximate stardate of discovery + (27, 'Jadzia Dax', 26, 2341.00), + (28, 'Julian Bashir', 27, 2341.00), + (29, 'Quark', 28, 2333.00), + (30, 'Jake Sisko', 29, 2355.00), + (31, 'Jonathan Archer', 30, 2112.00), + (32, 'T''Pol', 31, 2088.00), + (33, 'Phlox', 32, 2102.00), + (34, 'Charles "Trip" Tucker III', 33, 2121.00), + (35, 'Malcolm Reed', 34, 2117.00), + (36, 'Hoshi Sato', 35, 2129.00), + (37, 'Travis Mayweather', 36, 2126.00); + +INSERT INTO Series_Character (SeriesId, CharacterId, Role) VALUES + (1, 1, 'Captain'), -- James T. Kirk in Star Trek + (1, 2, 'Science Officer'), -- Spock in Star Trek + (1, 3, 'Doctor'), -- Leonard McCoy in Star Trek + (1, 4, 'Engineer'), -- Montgomery Scott in Star Trek + (1, 5, 'Communications Officer'), -- Uhura in Star Trek + (1, 6, 'Helmsman'), -- Hikaru Sulu in Star Trek + (1, 7, 'Navigator'), -- Pavel Chekov in Star Trek + (2, 8, 'Captain'), -- Jean-Luc Picard in Star Trek: The Next Generation + (2, 9, 'First Officer'), -- William Riker in Star Trek: The Next Generation + (2, 10, 'Operations Officer'),-- Data in Star Trek: The Next Generation + (2, 11, 'Security Officer'),-- Worf in Star Trek: The Next Generation + (2, 12, 'Doctor'),-- Beverly Crusher in Star Trek: The Next Generation + (2, 13, 'Counselor'),-- Deanna Troi in Star Trek: The Next Generation + (2, 14, 'Engineer'),-- Geordi La Forge in Star Trek: The Next Generation + (3, 15, 'Captain'),-- Kathryn Janeway in Star Trek: Voyager + (3, 16, 'First Officer'),-- Chakotay in Star Trek: Voyager + (3, 17, 'Tactical Officer'),-- Tuvok in Star Trek: Voyager + (3, 18, 'Engineer'),-- B'Elanna Torres in Star Trek: Voyager + (3, 19, 'Helmsman'),-- Tom Paris in Star Trek: Voyager + (3, 20, 'Operations Officer'),-- Harry Kim in Star Trek: Voyager + (3, 21, 'Doctor'),-- The Doctor in Star Trek: Voyager + (3, 22, 'Astrometrics Officer'),-- Seven of Nine in Star Trek: Voyager + (4, 23, 'Commanding Officer'),-- Benjamin Sisko in Star Trek: Deep Space Nine + (4, 24, 'First Officer'),-- Kira Nerys in Star Trek: Deep Space Nine + (4, 25, 'Security Officer'),-- Odo in Star Trek: Deep Space Nine + (4, 11, 'Strategic Operations Officer'),-- Worf in Star Trek: Deep Space Nine + (4, 27, 'Science Officer'),-- Jadzia Dax in Star Trek: Deep Space Nine + (4, 28, 'Doctor'),-- Julian Bashir in Star Trek: Deep Space Nine + (4, 29, 'Bar Owner'),-- Quark in Star Trek: Deep Space Nine + (4, 30, 'Civilian'),-- Jake Sisko in Star Trek: Deep Space Nine + (5, 31, 'Captain'),-- Jonathan Archer in Star Trek: Enterprise + (5, 32, 'Science Officer'),-- T'Pol in Star Trek: Enterprise + (5, 33, 'Doctor'),-- Phlox in Star Trek: Enterprise + (5, 34, 'Chief Engineer'),-- Charles "Trip" Tucker III in Star Trek: Enterprise + (5, 35, 'Armory Officer'),-- Malcolm Reed in Star Trek: Enterprise + (5, 36, 'Communications Officer'),-- Hoshi Sato in Star Trek: Enterprise + (5, 37, 'Helmsman');-- Travis Mayweather in Star Trek: Enterprise + +INSERT INTO Character_Species (CharacterId, SpeciesId) VALUES + (1, 1), -- James T. Kirk is Human + (2, 2), -- Spock is Vulcan + (2, 1), -- Spock is also Human + (3, 1), -- Leonard McCoy is Human + (4, 1), -- Montgomery Scott is Human + (5, 1), -- Uhura is Human + (6, 1), -- Hikaru Sulu is Human + (7, 1), -- Pavel Chekov is Human + (8, 1), -- Jean-Luc Picard is Human + (9, 1), -- William Riker is Human + (10, 3), -- Data is Android + (11, 4), -- Worf is Klingon + (12, 1), -- Beverly Crusher is Human + (13, 1), -- Deanna Troi is Human + (13, 5), -- Deanna Troi is also Betazoid + (14, 1), -- Geordi La Forge is Human + (15, 1), -- Kathryn Janeway is Human + (16, 1), -- Chakotay is Human + (17, 2), -- Tuvok is Vulcan + (18, 1), -- B'Elanna Torres is Human + (18, 4), -- B'Elanna Torres is also Klingon + (19, 1), -- Tom Paris is Human + (20, 1), -- Harry Kim is Human + (21, 6), -- The Doctor is a Hologram + (22, 1), -- Seven of Nine is Human + (22, 12),-- Seven of Nine is also Borg + (23, 1), -- Benjamin Sisko is Human + (24, 7), -- Kira Nerys is Bajoran + (25, 8), -- Odo is Changeling + (27, 9), -- Jadzia Dax is Trill + (28, 1), -- Julian Bashir is Human + (29, 10),-- Quark is Ferengi + (30, 1), -- Jake Sisko is Human + (31, 1), -- Jonathan Archer is Human + (32, 2), -- T'Pol is Vulcan + (33, 11),-- Phlox is Denobulan + (34, 1), -- Charles "Trip" Tucker III is Human + (35, 1), -- Malcolm Reed is Human + (36, 1), -- Hoshi Sato is Human + (37, 1); -- Travis Mayweather is Human \ No newline at end of file From af9d3e726022efa7824b7b8bd9fcc63b634e19f6 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Fri, 1 Aug 2025 14:22:44 -0700 Subject: [PATCH 02/12] OMG WE GOT THE HEALTH CHECK WORKING --- src/Service/HealthCheck/HealthCheckHelper.cs | 11 +- src/Service/HealthCheck/HttpUtilities.cs | 30 ++- src/Service/HealthCheck/Utilities.cs | 18 ++ src/Service/dab-config.json | 231 ++++++++++++++++++ src/apphost/AppHost.cs | 37 +-- .../init-scripts/pg/create-database-pg.sql | 87 ++++--- 6 files changed, 338 insertions(+), 76 deletions(-) create mode 100644 src/Service/dab-config.json diff --git a/src/Service/HealthCheck/HealthCheckHelper.cs b/src/Service/HealthCheck/HealthCheckHelper.cs index addb6b582a..c8ef96148b 100644 --- a/src/Service/HealthCheck/HealthCheckHelper.cs +++ b/src/Service/HealthCheck/HealthCheckHelper.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Data.Common; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; @@ -44,7 +45,7 @@ public HealthCheckHelper(ILogger logger, HttpUtilities httpUt /// /// GetHealthCheckResponse is the main function which fetches the HttpContext and then creates the comprehensive health check report. - /// Serializes the report to JSON and returns the response. + /// Serializes the report to JSON and returns the response. /// /// RuntimeConfig /// This function returns the comprehensive health report after calculating the response time of each datasource, rest and graphql health queries. @@ -160,7 +161,7 @@ private async Task UpdateDataSourceHealthCheckResultsAsync(ComprehensiveHealthCh if (ComprehensiveHealthCheckReport.Checks != null && runtimeConfig.DataSource.IsDatasourceHealthEnabled) { string query = Utilities.GetDatSourceQuery(runtimeConfig.DataSource.DatabaseType); - (int, string?) response = await ExecuteDatasourceQueryCheckAsync(query, runtimeConfig.DataSource.ConnectionString); + (int, string?) response = await ExecuteDatasourceQueryCheckAsync(query, runtimeConfig.DataSource.ConnectionString, Utilities.GetDbProviderFactory(runtimeConfig.DataSource.DatabaseType)); bool isResponseTimeWithinThreshold = response.Item1 >= 0 && response.Item1 < runtimeConfig.DataSource.DatasourceThresholdMs; // Add DataSource Health Check Results @@ -180,14 +181,14 @@ private async Task UpdateDataSourceHealthCheckResultsAsync(ComprehensiveHealthCh } // Executes the DB Query and keeps track of the response time and error message. - private async Task<(int, string?)> ExecuteDatasourceQueryCheckAsync(string query, string connectionString) + private async Task<(int, string?)> ExecuteDatasourceQueryCheckAsync(string query, string connectionString, DbProviderFactory dbProviderFactory) { string? errorMessage = null; if (!string.IsNullOrEmpty(query) && !string.IsNullOrEmpty(connectionString)) { Stopwatch stopwatch = new(); stopwatch.Start(); - errorMessage = await _httpUtility.ExecuteDbQueryAsync(query, connectionString); + errorMessage = await _httpUtility.ExecuteDbQueryAsync(query, connectionString, dbProviderFactory); stopwatch.Stop(); return string.IsNullOrEmpty(errorMessage) ? ((int)stopwatch.ElapsedMilliseconds, errorMessage) : (HealthCheckConstants.ERROR_RESPONSE_TIME_MS, errorMessage); } @@ -195,7 +196,7 @@ private async Task UpdateDataSourceHealthCheckResultsAsync(ComprehensiveHealthCh return (HealthCheckConstants.ERROR_RESPONSE_TIME_MS, errorMessage); } - // Updates the Entity Health Check Results in the response. + // Updates the Entity Health Check Results in the response. // Goes through the entities one by one and executes the rest and graphql checks (if enabled). private async Task UpdateEntityHealthCheckResultsAsync(ComprehensiveHealthCheckReport report, RuntimeConfig runtimeConfig) { diff --git a/src/Service/HealthCheck/HttpUtilities.cs b/src/Service/HealthCheck/HttpUtilities.cs index a3195d0d8a..113e731bb6 100644 --- a/src/Service/HealthCheck/HttpUtilities.cs +++ b/src/Service/HealthCheck/HttpUtilities.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Data.Common; using System.Linq; using System.Net.Http; using System.Text; @@ -14,7 +15,6 @@ using Azure.DataApiBuilder.Core.Services; using Azure.DataApiBuilder.Core.Services.MetadataProviders; using Azure.DataApiBuilder.Service.GraphQLBuilder; -using Microsoft.Data.SqlClient; using Microsoft.Extensions.Logging; namespace Azure.DataApiBuilder.Service.HealthCheck @@ -49,19 +49,31 @@ public HttpUtilities( } // Executes the DB query by establishing a connection to the DB. - public async Task ExecuteDbQueryAsync(string query, string connectionString) + public async Task ExecuteDbQueryAsync(string query, string connectionString, DbProviderFactory providerFactory) { string? errorMessage = null; // Execute the query on DB and return the response time. - using (SqlConnection connection = new(connectionString)) + using (DbConnection? connection = providerFactory.CreateConnection()) { + if (connection == null) + { + errorMessage = "Failed to create database connection."; + _logger.LogError(errorMessage); + return errorMessage; + } + try { - SqlCommand command = new(query, connection); - connection.Open(); - SqlDataReader reader = await command.ExecuteReaderAsync(); - _logger.LogTrace("The health check query for datasource executed successfully."); - reader.Close(); + connection.ConnectionString = connectionString; + using (DbCommand command = connection.CreateCommand()) + { + command.CommandText = query; + await connection.OpenAsync(); + using (DbDataReader reader = await command.ExecuteReaderAsync()) + { + _logger.LogTrace("The health check query for datasource executed successfully."); + } + } } catch (Exception ex) { @@ -145,7 +157,7 @@ public HttpUtilities( List columnNames = dbObject.SourceDefinition.Columns.Keys.ToList(); // In case of GraphQL API, use the plural value specified in [entity.graphql.type.plural]. - // Further, we need to camel case this plural value to match the GraphQL object name. + // Further, we need to camel case this plural value to match the GraphQL object name. string graphqlObjectName = GraphQLNaming.GenerateListQueryName(entityName, entity); // In case any primitive column names are present, execute the query diff --git a/src/Service/HealthCheck/Utilities.cs b/src/Service/HealthCheck/Utilities.cs index 4b61346736..290410291e 100644 --- a/src/Service/HealthCheck/Utilities.cs +++ b/src/Service/HealthCheck/Utilities.cs @@ -1,9 +1,13 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using System; using System.Collections.Generic; +using System.Data.Common; using System.Text.Json; using Azure.DataApiBuilder.Config.ObjectModel; +using Microsoft.Data.SqlClient; +using Npgsql; namespace Azure.DataApiBuilder.Service.HealthCheck { @@ -32,6 +36,20 @@ public static string GetDatSourceQuery(DatabaseType dbType) } } + public static DbProviderFactory GetDbProviderFactory(DatabaseType dbType) + { + switch (dbType) + { + case DatabaseType.PostgreSQL: + return NpgsqlFactory.Instance; + case DatabaseType.MSSQL: + case DatabaseType.DWSQL: + return SqlClientFactory.Instance; + default: + throw new NotSupportedException($"Database type '{dbType}' is not supported."); + } + } + public static string CreateHttpGraphQLQuery(string entityName, List columnNames, int first) { var payload = new diff --git a/src/Service/dab-config.json b/src/Service/dab-config.json new file mode 100644 index 0000000000..b713ad2531 --- /dev/null +++ b/src/Service/dab-config.json @@ -0,0 +1,231 @@ +{ + "data-source": { + "database-type": "@env('db-type')", + "connection-string": "@env('ConnectionStrings__Trek')", + "options": { + "set-session-context": false + } + }, + "runtime": { + "rest": { + "enabled": true, + "path": "/api", + "request-body-strict": true + }, + "graphql": { + "enabled": true, + "path": "/graphql", + "allow-introspection": true + }, + "host": { + "authentication": { + "provider": "StaticWebApps" + }, + "cors": { + "origins": [], + "allow-credentials": false + }, + "mode": "development" + }, + "telemetry": { + "open-telemetry": { + "enabled": true, + "endpoint": "@env('OTEL_EXPORTER_OTLP_ENDPOINT')", + "headers": "@env('OTEL_EXPORTER_OTLP_HEADERS')", + "exporter-protocol": "@env('OTEL_EXPORTER_OTLP_PROTOCOL')", + "service-name": "@env('OTEL_SERVICE_NAME')" + } + }, + "cache": { + "enabled": true, + "ttl-seconds": 60 + } + }, + "entities": { + "Actor": { + "source": { + "object": "Actor", + "type": "table" + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Actor", + "plural": "Actors" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + "*" + ] + } + ], + "relationships": { + "character": { + "cardinality": "many", + "target.entity": "Character", + "source.fields": [ + "Id" + ], + "target.fields": [ + "ActorId" + ], + "linking.source.fields": [], + "linking.target.fields": [] + } + } + }, + "Character": { + "source": { + "object": "Character", + "type": "table" + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Character", + "plural": "Characters" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ], + "relationships": { + "actor": { + "cardinality": "one", + "target.entity": "Actor", + "source.fields": [ + "ActorId" + ], + "target.fields": [ + "Id" + ], + "linking.source.fields": [], + "linking.target.fields": [] + }, + "series": { + "cardinality": "many", + "target.entity": "Series", + "source.fields": [ + "Id" + ], + "target.fields": [ + "Id" + ], + "linking.object": "series_character", + "linking.source.fields": [ + "CharacterId" + ], + "linking.target.fields": [ + "SeriesId" + ] + } + } + }, + "Series": { + "source": { + "object": "Series", + "type": "table" + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Series", + "plural": "Series" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ], + "relationships": { + "character": { + "cardinality": "many", + "target.entity": "Character", + "source.fields": [ + "Id" + ], + "target.fields": [ + "Id" + ], + "linking.object": "series_character", + "linking.source.fields": [ + "SeriesId" + ], + "linking.target.fields": [ + "CharacterId" + ] + } + } + }, + "Species": { + "source": { + "object": "Species", + "type": "table" + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Species", + "plural": "Species" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ], + "relationships": { + "character": { + "cardinality": "many", + "target.entity": "Character", + "source.fields": [ + "Id" + ], + "target.fields": [ + "Id" + ], + "linking.object": "character_species", + "linking.source.fields": [ + "SpeciesId" + ], + "linking.target.fields": [ + "CharacterId" + ] + } + } + } + } + } diff --git a/src/apphost/AppHost.cs b/src/apphost/AppHost.cs index 7ce1986c46..d7a9140c04 100644 --- a/src/apphost/AppHost.cs +++ b/src/apphost/AppHost.cs @@ -9,19 +9,18 @@ var msSql = sqlDbContainer.AddDatabase("msSqlDb", "Trek") .WithCreationScript(sqlScript); +var pgScript = File.ReadAllText("./init-scripts/pg/create-database-pg.sql"); + var postgresDB = builder.AddPostgres("postgres") - .WithDataVolume() + //.WithDataVolume() .WithPgAdmin() - .WithInitFiles("./init-scripts/pg") - .WithLifetime(ContainerLifetime.Persistent) - .AddDatabase("pgSqlDb", "Trek"); + .AddDatabase("pgDb", "postgres") + .WithCreationScript(pgScript); -builder.AddProject("mssql-service", "Development") +var mssqlService = builder.AddProject("mssql-service", "Development") .WithArgs("-f", "net8.0") - .WithEndpoint(endpointName: "https", (e) => - { - e.Port = 6834; - }) + .WithEndpoint(endpointName: "https", (e) => e.Port = 6834) + .WithEndpoint(endpointName: "http", (e) => e.Port = 8834) .WithEnvironment("ConnectionStrings__Trek", msSql) .WithEnvironment("db-type", "mssql") .WithUrls((e) => @@ -31,14 +30,13 @@ e.Urls.Add(new() { Url = "/graphql", DisplayText = "🔒GraphQL", Endpoint = e.GetEndpoint("https") }); }) .WithHttpHealthCheck("/health") - .WaitFor(msSql); + .WaitFor(msSql) + .WithExplicitStart(); -builder.AddProject("pg-service", "Development") +var pgService = builder.AddProject("pg-service", "Development") .WithArgs("-f", "net8.0") - .WithEndpoint(endpointName: "https", (e) => - { - e.Port = 7834; - }) + .WithEndpoint(endpointName: "https", (e) => e.Port = 7834) + .WithEndpoint(endpointName: "http", (e) => e.Port = 5834) .WithEnvironment("ConnectionStrings__Trek", postgresDB) .WithEnvironment("db-type", "postgresql") .WithUrls((e) => @@ -48,6 +46,13 @@ e.Urls.Add(new() { Url = "/graphql", DisplayText = "🔒GraphQL", Endpoint = e.GetEndpoint("https") }); }) .WithHttpHealthCheck("/health") - .WaitFor(postgresDB); + .WaitFor(postgresDB) + .WithExplicitStart(); + +// BUG: Blocked due to https://github.com/dotnet/aspire/issues/10680 +// msSql.WithParentRelationship(mssqlService); + +// YOU NEED TO HAVE A SPACE HERE OR ELSE THIS DOESN'T WORK, WHAT EVEN IF THIS, PYTHON!?!?! +// postgresDB.WithParentRelationship(pgService); builder.Build().Run(); diff --git a/src/apphost/init-scripts/pg/create-database-pg.sql b/src/apphost/init-scripts/pg/create-database-pg.sql index 3b063e9dbf..73adccc008 100644 --- a/src/apphost/init-scripts/pg/create-database-pg.sql +++ b/src/apphost/init-scripts/pg/create-database-pg.sql @@ -3,75 +3,70 @@ -- Create database (run this as a superuser, outside the target database) -- Uncomment and edit the database name as needed --- CREATE DATABASE "Trek" --- WITH --- OWNER = trek_user --- ENCODING = 'UTF8' --- LC_COLLATE = 'en_US.utf8' --- LC_CTYPE = 'en_US.utf8' --- TEMPLATE = template0; +--CREATE DATABASE "Trek"; -- Connect to the target database before running the rest of the script +--\connect Trek; -- Drop tables in reverse order of creation due to foreign key dependencies -DROP TABLE IF EXISTS Character_Species; -DROP TABLE IF EXISTS Series_Character; +DROP TABLE IF EXISTS "Character_Species"; +DROP TABLE IF EXISTS "Series_Character"; DROP TABLE IF EXISTS "Character"; -DROP TABLE IF EXISTS Species; -DROP TABLE IF EXISTS Actor; -DROP TABLE IF EXISTS Series; +DROP TABLE IF EXISTS "Species"; +DROP TABLE IF EXISTS "Actor"; +DROP TABLE IF EXISTS "Series"; -- create tables -CREATE TABLE Series ( - Id INTEGER PRIMARY KEY, - Name VARCHAR(255) NOT NULL +CREATE TABLE "Series" ( + "Id" INTEGER PRIMARY KEY, + "Name" VARCHAR(255) NOT NULL ); -CREATE TABLE Actor ( - Id INTEGER PRIMARY KEY, - Name VARCHAR(255) NOT NULL, +CREATE TABLE "Actor" ( + "Id" INTEGER PRIMARY KEY, + "Name" VARCHAR(255) NOT NULL, "BirthYear" INTEGER NOT NULL ); -CREATE TABLE Species ( - Id INTEGER PRIMARY KEY, - Name VARCHAR(255) NOT NULL +CREATE TABLE "Species" ( + "Id" INTEGER PRIMARY KEY, + "Name" VARCHAR(255) NOT NULL ); CREATE TABLE "Character" ( - Id INTEGER PRIMARY KEY, - Name VARCHAR(255) NOT NULL, - ActorId INTEGER NOT NULL, - Stardate DECIMAL(10, 2), - FOREIGN KEY (ActorId) REFERENCES Actor(Id) + "Id" INTEGER PRIMARY KEY, + "Name" VARCHAR(255) NOT NULL, + "ActorId" INTEGER NOT NULL, + "Stardate" DECIMAL(10, 2), + FOREIGN KEY ("ActorId") REFERENCES "Actor"("Id") ); -CREATE TABLE Series_Character ( - SeriesId INTEGER, - CharacterId INTEGER, - Role VARCHAR(500), - FOREIGN KEY (SeriesId) REFERENCES Series(Id), - FOREIGN KEY (CharacterId) REFERENCES "Character"(Id), - PRIMARY KEY (SeriesId, CharacterId) +CREATE TABLE "Series_Character" ( + "SeriesId" INTEGER, + "CharacterId" INTEGER, + "Role" VARCHAR(500), + FOREIGN KEY ("SeriesId") REFERENCES "Series"("Id"), + FOREIGN KEY ("CharacterId") REFERENCES "Character"("Id"), + PRIMARY KEY ("SeriesId", "CharacterId") ); -CREATE TABLE Character_Species ( - CharacterId INTEGER, - SpeciesId INTEGER, - FOREIGN KEY (CharacterId) REFERENCES "Character"(Id), - FOREIGN KEY (SpeciesId) REFERENCES Species(Id), - PRIMARY KEY (CharacterId, SpeciesId) +CREATE TABLE "Character_Species" ( + "CharacterId" INTEGER, + "SpeciesId" INTEGER, + FOREIGN KEY ("CharacterId") REFERENCES "Character"("Id"), + FOREIGN KEY ("SpeciesId") REFERENCES "Species"("Id"), + PRIMARY KEY ("CharacterId", "SpeciesId") ); -- create data -INSERT INTO Series (Id, Name) VALUES +INSERT INTO "Series" ("Id", "Name") VALUES (1, 'Star Trek'), (2, 'Star Trek: The Next Generation'), (3, 'Star Trek: Voyager'), (4, 'Star Trek: Deep Space Nine'), (5, 'Star Trek: Enterprise'); -INSERT INTO Species (Id, Name) VALUES +INSERT INTO "Species" ("Id", "Name") VALUES (1, 'Human'), (2, 'Vulcan'), (3, 'Android'), @@ -85,7 +80,7 @@ INSERT INTO Species (Id, Name) VALUES (11, 'Denobulan'), (12, 'Borg'); -INSERT INTO Actor (Id, Name, "BirthYear") VALUES +INSERT INTO "Actor" ("Id", "Name", "BirthYear") VALUES (1, 'William Shatner', 1931), (2, 'Leonard Nimoy', 1931), (3, 'DeForest Kelley', 1920), @@ -123,7 +118,7 @@ INSERT INTO Actor (Id, Name, "BirthYear") VALUES (35, 'Linda Park', 1978), (36, 'Anthony Montgomery', 1971); -INSERT INTO "Character" (Id, Name, ActorId, Stardate) VALUES +INSERT INTO "Character" ("Id", "Name", "ActorId", "Stardate") VALUES (1, 'James T. Kirk', 1, 2233.04), (2, 'Spock', 2, 2230.06), (3, 'Leonard McCoy', 3, 2227.00), @@ -161,7 +156,7 @@ INSERT INTO "Character" (Id, Name, ActorId, Stardate) VALUES (36, 'Hoshi Sato', 35, 2129.00), (37, 'Travis Mayweather', 36, 2126.00); -INSERT INTO Series_Character (SeriesId, CharacterId, Role) VALUES +INSERT INTO "Series_Character" ("SeriesId", "CharacterId", "Role") VALUES (1, 1, 'Captain'), -- James T. Kirk in Star Trek (1, 2, 'Science Officer'), -- Spock in Star Trek (1, 3, 'Doctor'), -- Leonard McCoy in Star Trek @@ -200,7 +195,7 @@ INSERT INTO Series_Character (SeriesId, CharacterId, Role) VALUES (5, 36, 'Communications Officer'),-- Hoshi Sato in Star Trek: Enterprise (5, 37, 'Helmsman');-- Travis Mayweather in Star Trek: Enterprise -INSERT INTO Character_Species (CharacterId, SpeciesId) VALUES +INSERT INTO "Character_Species" ("CharacterId", "SpeciesId") VALUES (1, 1), -- James T. Kirk is Human (2, 2), -- Spock is Vulcan (2, 1), -- Spock is also Human @@ -240,4 +235,4 @@ INSERT INTO Character_Species (CharacterId, SpeciesId) VALUES (34, 1), -- Charles "Trip" Tucker III is Human (35, 1), -- Malcolm Reed is Human (36, 1), -- Hoshi Sato is Human - (37, 1); -- Travis Mayweather is Human \ No newline at end of file + (37, 1); -- Travis Mayweather is Human From 8e3b98f6a2015caec9dec4d934c0ad8a3011d3f0 Mon Sep 17 00:00:00 2001 From: "Maddy Montaquila (Leger)" Date: Fri, 22 Aug 2025 13:36:15 -0400 Subject: [PATCH 03/12] Update src/apphost/AppHost.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/apphost/AppHost.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/apphost/AppHost.cs b/src/apphost/AppHost.cs index d7a9140c04..85fbe06fe2 100644 --- a/src/apphost/AppHost.cs +++ b/src/apphost/AppHost.cs @@ -12,7 +12,6 @@ var pgScript = File.ReadAllText("./init-scripts/pg/create-database-pg.sql"); var postgresDB = builder.AddPostgres("postgres") - //.WithDataVolume() .WithPgAdmin() .AddDatabase("pgDb", "postgres") .WithCreationScript(pgScript); From d2cbdf22bcfa1f53b97294102d2bf6d5d2a0d104 Mon Sep 17 00:00:00 2001 From: "Maddy Montaquila (Leger)" Date: Fri, 22 Aug 2025 13:36:24 -0400 Subject: [PATCH 04/12] Update .aspire/settings.json Co-authored-by: Aniruddh Munde --- .aspire/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.aspire/settings.json b/.aspire/settings.json index 71d0d3f204..1d2efd6517 100644 --- a/.aspire/settings.json +++ b/.aspire/settings.json @@ -1,3 +1,3 @@ { "appHostPath": "../src/apphost/apphost.csproj" -} \ No newline at end of file +} From eff9d0743533ec319d9903eff42fa84076343cd3 Mon Sep 17 00:00:00 2001 From: "Maddy Montaquila (Leger)" Date: Fri, 22 Aug 2025 13:36:56 -0400 Subject: [PATCH 05/12] Update src/apphost/AppHost.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/apphost/AppHost.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apphost/AppHost.cs b/src/apphost/AppHost.cs index 85fbe06fe2..2c9c58429c 100644 --- a/src/apphost/AppHost.cs +++ b/src/apphost/AppHost.cs @@ -51,7 +51,7 @@ // BUG: Blocked due to https://github.com/dotnet/aspire/issues/10680 // msSql.WithParentRelationship(mssqlService); -// YOU NEED TO HAVE A SPACE HERE OR ELSE THIS DOESN'T WORK, WHAT EVEN IF THIS, PYTHON!?!?! +// Note: A space is required here due to a parsing issue in the framework. Without the space, the parent relationship may not be established correctly. See related issue: https://github.com/dotnet/aspire/issues/10680 // postgresDB.WithParentRelationship(pgService); builder.Build().Run(); From 14ef69d9f02fa6656ef27b4df4b292ee4dfa2acc Mon Sep 17 00:00:00 2001 From: "Maddy Montaquila (Leger)" Date: Fri, 22 Aug 2025 13:37:13 -0400 Subject: [PATCH 06/12] Update src/apphost/init-scripts/create-database.sql Co-authored-by: Aniruddh Munde --- src/apphost/init-scripts/create-database.sql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/apphost/init-scripts/create-database.sql b/src/apphost/init-scripts/create-database.sql index cef265a293..a12c71138e 100644 --- a/src/apphost/init-scripts/create-database.sql +++ b/src/apphost/init-scripts/create-database.sql @@ -235,4 +235,5 @@ INSERT INTO Character_Species (CharacterId, SpeciesId) VALUES (34, 1), -- Charles "Trip" Tucker III is Human (35, 1), -- Malcolm Reed is Human (36, 1), -- Hoshi Sato is Human - (37, 1); -- Travis Mayweather is Human \ No newline at end of file + (37, 1); -- Travis Mayweather is Human + \ No newline at end of file From f8085ec7d7b9652a8a1000788e0c83329b7d6a78 Mon Sep 17 00:00:00 2001 From: Maddy Montaquila Date: Fri, 22 Aug 2025 16:51:41 -0400 Subject: [PATCH 07/12] code review edits --- Nuget.config | 3 +-- src/Service/HealthCheck/HttpUtilities.cs | 15 ++++++++------- src/apphost/apphost.csproj.Backup.tmp | 21 --------------------- 3 files changed, 9 insertions(+), 30 deletions(-) delete mode 100644 src/apphost/apphost.csproj.Backup.tmp diff --git a/Nuget.config b/Nuget.config index fd8d459f1a..704c9d13ba 100644 --- a/Nuget.config +++ b/Nuget.config @@ -2,8 +2,7 @@ - - + diff --git a/src/Service/HealthCheck/HttpUtilities.cs b/src/Service/HealthCheck/HttpUtilities.cs index 113e731bb6..9da596ae30 100644 --- a/src/Service/HealthCheck/HttpUtilities.cs +++ b/src/Service/HealthCheck/HttpUtilities.cs @@ -53,15 +53,16 @@ public HttpUtilities( { string? errorMessage = null; // Execute the query on DB and return the response time. - using (DbConnection? connection = providerFactory.CreateConnection()) + DbConnection? connection = providerFactory.CreateConnection(); + if (connection == null) { - if (connection == null) - { - errorMessage = "Failed to create database connection."; - _logger.LogError(errorMessage); - return errorMessage; - } + errorMessage = "Failed to create database connection."; + _logger.LogError(errorMessage); + return errorMessage; + } + using (connection) + { try { connection.ConnectionString = connectionString; diff --git a/src/apphost/apphost.csproj.Backup.tmp b/src/apphost/apphost.csproj.Backup.tmp deleted file mode 100644 index 088efcfc83..0000000000 --- a/src/apphost/apphost.csproj.Backup.tmp +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - Exe - net8.0 - enable - enable - f08719fd-267f-459e-9980-77b1c52c8755 - - - - - - - - - - - From 499701551493f452160f72ab0f4e779b82b7704c Mon Sep 17 00:00:00 2001 From: Tommaso Stocchi Date: Fri, 5 Sep 2025 19:53:42 +0200 Subject: [PATCH 08/12] adds launch profiles to switch between different db types --- .aspire/settings.json | 4 +- src/Aspire.AppHost/AppHost.cs | 95 +++++++++++++++++++ .../Aspire.AppHost.csproj} | 0 src/Aspire.AppHost/DockerStatus.cs | 26 +++++ .../Properties/launchSettings.json | 57 +++++++++++ src/Aspire.AppHost/README.md | 17 ++++ .../appsettings.json | 0 .../init-scripts/pg/create-database-pg.sql | 0 .../init-scripts/sql}/create-database.sql | 0 src/Azure.DataApiBuilder.sln | 5 +- .../Azure.DataApiBuilder.Service.csproj | 2 +- src/Service/dab-config.json | 14 +-- src/apphost/AppHost.cs | 57 ----------- src/apphost/Properties/launchSettings.json | 29 ------ 14 files changed, 208 insertions(+), 98 deletions(-) create mode 100644 src/Aspire.AppHost/AppHost.cs rename src/{apphost/apphost.csproj => Aspire.AppHost/Aspire.AppHost.csproj} (100%) create mode 100644 src/Aspire.AppHost/DockerStatus.cs create mode 100644 src/Aspire.AppHost/Properties/launchSettings.json create mode 100644 src/Aspire.AppHost/README.md rename src/{apphost => Aspire.AppHost}/appsettings.json (100%) rename src/{apphost => Aspire.AppHost}/init-scripts/pg/create-database-pg.sql (100%) rename src/{apphost/init-scripts => Aspire.AppHost/init-scripts/sql}/create-database.sql (100%) delete mode 100644 src/apphost/AppHost.cs delete mode 100644 src/apphost/Properties/launchSettings.json diff --git a/.aspire/settings.json b/.aspire/settings.json index 1d2efd6517..61dd69a516 100644 --- a/.aspire/settings.json +++ b/.aspire/settings.json @@ -1,3 +1,3 @@ { - "appHostPath": "../src/apphost/apphost.csproj" -} + "appHostPath": "../src/Aspire.AppHost/Aspire.AppHost.csproj" +} \ No newline at end of file diff --git a/src/Aspire.AppHost/AppHost.cs b/src/Aspire.AppHost/AppHost.cs new file mode 100644 index 0000000000..597902e9f1 --- /dev/null +++ b/src/Aspire.AppHost/AppHost.cs @@ -0,0 +1,95 @@ +using Microsoft.Extensions.DependencyInjection; + +var builder = DistributedApplication.CreateBuilder(args); + +var aspireDB = Environment.GetEnvironmentVariable("ASPIRE_DATABASE_TYPE"); + +var databaseConnectionString = Environment.GetEnvironmentVariable("ASPIRE_DATABASE_CONNECTION_STRING") ?? ""; + +switch (aspireDB) +{ + case "sql": + var sqlScript = File.ReadAllText("./init-scripts/sql/create-database.sql"); + + IResourceBuilder? sqlDbContainer = null; + + if(string.IsNullOrEmpty(databaseConnectionString)) + { + Console.WriteLine("No connection string provided, starting a local SQL Server container."); + + sqlDbContainer = builder.AddSqlServer("sqlserver") + .WithDataVolume() + .WithLifetime(ContainerLifetime.Persistent) + .AddDatabase("msSqlDb", "Trek") + .WithCreationScript(sqlScript); + } + + var mssqlService = builder.AddProject("mssql-service", "Development") + .WithArgs("-f", "net8.0") + .WithEndpoint(endpointName: "https", (e) => e.Port = 1234) + .WithEndpoint(endpointName: "http", (e) => e.Port = 2345) + .WithEnvironment("db-type", "mssql") + .WithUrls((e) => + { + e.Urls.Clear(); + e.Urls.Add(new() { Url = "/swagger", DisplayText = "🔒Swagger", Endpoint = e.GetEndpoint("https") }); + e.Urls.Add(new() { Url = "/graphql", DisplayText = "🔒GraphQL", Endpoint = e.GetEndpoint("https") }); + }) + .WithHttpHealthCheck("/health"); + + if (sqlDbContainer is null) + { + mssqlService.WithEnvironment("ConnectionStrings__Database", databaseConnectionString); + } + else + { + mssqlService.WithEnvironment("ConnectionStrings__Database", sqlDbContainer) + .WaitFor(sqlDbContainer); + } + + break; + case "postgres": + var pgScript = File.ReadAllText("./init-scripts/pg/create-database-pg.sql"); + + IResourceBuilder? postgresDB = null; + + if (!string.IsNullOrEmpty(databaseConnectionString)) + { + Console.WriteLine("No connection string provided, starting a local PostgreSQL container."); + + postgresDB = builder.AddPostgres("postgres") + .WithPgAdmin() + .WithLifetime(ContainerLifetime.Persistent) + .AddDatabase("pgDb", "postgres") + .WithCreationScript(pgScript); + } + + var pgService = builder.AddProject("pg-service", "Development") + .WithArgs("-f", "net8.0") + .WithEndpoint(endpointName: "https", (e) => e.Port = 1234) + .WithEndpoint(endpointName: "http", (e) => e.Port = 2345) + .WithEnvironment("db-type", "postgresql") + .WithUrls((e) => + { + e.Urls.Clear(); + e.Urls.Add(new() { Url = "/swagger", DisplayText = "🔒Swagger", Endpoint = e.GetEndpoint("https") }); + e.Urls.Add(new() { Url = "/graphql", DisplayText = "🔒GraphQL", Endpoint = e.GetEndpoint("https") }); + }) + .WithHttpHealthCheck("/health"); + + if (postgresDB is null) + { + pgService.WithEnvironment("ConnectionStrings__Database", databaseConnectionString); + } + else + { + pgService.WithEnvironment("ConnectionStrings__Database", postgresDB) + .WaitFor(postgresDB); + } + + break; + default: + throw new Exception("Please set the ASPIRE_DATABASE environment variable to either 'sql' or 'postgre'."); +} + +builder.Build().Run(); diff --git a/src/apphost/apphost.csproj b/src/Aspire.AppHost/Aspire.AppHost.csproj similarity index 100% rename from src/apphost/apphost.csproj rename to src/Aspire.AppHost/Aspire.AppHost.csproj diff --git a/src/Aspire.AppHost/DockerStatus.cs b/src/Aspire.AppHost/DockerStatus.cs new file mode 100644 index 0000000000..ad4237357e --- /dev/null +++ b/src/Aspire.AppHost/DockerStatus.cs @@ -0,0 +1,26 @@ +using System.Diagnostics; + +public static class DockerStatus +{ + public static async Task IsDockerRunningAsync() + { + var psi = new ProcessStartInfo + { + FileName = "docker", + Arguments = "info", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + }; + try + { + using var process = Process.Start(psi)!; + await process.WaitForExitAsync(); + return process.ExitCode == 0; + } + catch + { + return false; + } + } +} diff --git a/src/Aspire.AppHost/Properties/launchSettings.json b/src/Aspire.AppHost/Properties/launchSettings.json new file mode 100644 index 0000000000..ed07d15a0b --- /dev/null +++ b/src/Aspire.AppHost/Properties/launchSettings.json @@ -0,0 +1,57 @@ +{ + "profiles": { + "https": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21213", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22145" + }, + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:17047;http://localhost:15161" + }, + "http": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19015", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20166" + }, + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:15161" + }, + "aspire-sql": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21213", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22145", + "ASPIRE_DATABASE_TYPE": "sql", + "ASPIRE_DATABASE_CONNECTION_STRING": "" + }, + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:17047;http://localhost:15161" + }, + "aspire-postgres": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21213", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22145", + "ASPIRE_DATABASE_TYPE": "postgres", + "ASPIRE_DATABASE_CONNECTION_STRING": "" + }, + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:17047;http://localhost:15161" + } + }, + "$schema": "https://json.schemastore.org/launchsettings.json" +} diff --git a/src/Aspire.AppHost/README.md b/src/Aspire.AppHost/README.md new file mode 100644 index 0000000000..3437c367bb --- /dev/null +++ b/src/Aspire.AppHost/README.md @@ -0,0 +1,17 @@ +# Aspire Instructions + +This project allows you to run DAB in debug mode using [Aspire](https://learn.microsoft.com/en-us/dotnet/aspire/get-started/aspire-overview). + +## Prerequisites +- [.NET SDK](https://dotnet.microsoft.com/download) (8.0 or later) +- [Docker](https://www.docker.com/products/docker-desktop) (optional, for containerized development) + +## Database Configuration + +In the `launchProfile.json` file, you can configure the database connection string. If you don't, Aspire will start for you a local instance in a Docker container. + +Simply provide a value for the `ASPIRE_DATABASE_CONNECTION_STRING` environment variable. + +You can select to run Aspire with different databases selecting the appropriate launch profile: +- `aspire-sql` +- `aspire-postgres` diff --git a/src/apphost/appsettings.json b/src/Aspire.AppHost/appsettings.json similarity index 100% rename from src/apphost/appsettings.json rename to src/Aspire.AppHost/appsettings.json diff --git a/src/apphost/init-scripts/pg/create-database-pg.sql b/src/Aspire.AppHost/init-scripts/pg/create-database-pg.sql similarity index 100% rename from src/apphost/init-scripts/pg/create-database-pg.sql rename to src/Aspire.AppHost/init-scripts/pg/create-database-pg.sql diff --git a/src/apphost/init-scripts/create-database.sql b/src/Aspire.AppHost/init-scripts/sql/create-database.sql similarity index 100% rename from src/apphost/init-scripts/create-database.sql rename to src/Aspire.AppHost/init-scripts/sql/create-database.sql diff --git a/src/Azure.DataApiBuilder.sln b/src/Azure.DataApiBuilder.sln index bdbfe3a092..f3b51ab559 100644 --- a/src/Azure.DataApiBuilder.sln +++ b/src/Azure.DataApiBuilder.sln @@ -1,4 +1,5 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 + +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.3.32405.409 MinimumVisualStudioVersion = 10.0.40219.1 @@ -31,7 +32,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.DataApiBuilder.Core", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.DataApiBuilder.Product", "Product\Azure.DataApiBuilder.Product.csproj", "{E3D2076C-EE49-43A0-8F92-5FC41EC99DA7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "apphost", "apphost\apphost.csproj", "{87B53030-EB52-4EB1-870D-72540DA4724E}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspire.AppHost", "Aspire.AppHost\Aspire.AppHost.csproj", "{87B53030-EB52-4EB1-870D-72540DA4724E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/Service/Azure.DataApiBuilder.Service.csproj b/src/Service/Azure.DataApiBuilder.Service.csproj index 9f1558e504..74ab1fe9b7 100644 --- a/src/Service/Azure.DataApiBuilder.Service.csproj +++ b/src/Service/Azure.DataApiBuilder.Service.csproj @@ -1,7 +1,7 @@ - net8.0 + net8.0 Debug;Release;Docker $(BaseOutputPath)\engine win-x64;linux-x64;osx-x64 diff --git a/src/Service/dab-config.json b/src/Service/dab-config.json index b713ad2531..859267100e 100644 --- a/src/Service/dab-config.json +++ b/src/Service/dab-config.json @@ -1,11 +1,11 @@ { - "data-source": { - "database-type": "@env('db-type')", - "connection-string": "@env('ConnectionStrings__Trek')", - "options": { - "set-session-context": false - } - }, + "data-source": { + "database-type": "@env('db-type')", + "connection-string": "@env('ConnectionStrings__Database')", + "options": { + "set-session-context": false + } + }, "runtime": { "rest": { "enabled": true, diff --git a/src/apphost/AppHost.cs b/src/apphost/AppHost.cs deleted file mode 100644 index 2c9c58429c..0000000000 --- a/src/apphost/AppHost.cs +++ /dev/null @@ -1,57 +0,0 @@ -var builder = DistributedApplication.CreateBuilder(args); - -var sqlDbContainer = builder.AddSqlServer("sqlserver") - .WithDataVolume() - .WithLifetime(ContainerLifetime.Persistent); - -var sqlScript = File.ReadAllText("./init-scripts/create-database.sql"); - -var msSql = sqlDbContainer.AddDatabase("msSqlDb", "Trek") - .WithCreationScript(sqlScript); - -var pgScript = File.ReadAllText("./init-scripts/pg/create-database-pg.sql"); - -var postgresDB = builder.AddPostgres("postgres") - .WithPgAdmin() - .AddDatabase("pgDb", "postgres") - .WithCreationScript(pgScript); - -var mssqlService = builder.AddProject("mssql-service", "Development") - .WithArgs("-f", "net8.0") - .WithEndpoint(endpointName: "https", (e) => e.Port = 6834) - .WithEndpoint(endpointName: "http", (e) => e.Port = 8834) - .WithEnvironment("ConnectionStrings__Trek", msSql) - .WithEnvironment("db-type", "mssql") - .WithUrls((e) => - { - e.Urls.Clear(); - e.Urls.Add(new() { Url = "/swagger", DisplayText = "🔒Swagger", Endpoint = e.GetEndpoint("https") }); - e.Urls.Add(new() { Url = "/graphql", DisplayText = "🔒GraphQL", Endpoint = e.GetEndpoint("https") }); - }) - .WithHttpHealthCheck("/health") - .WaitFor(msSql) - .WithExplicitStart(); - -var pgService = builder.AddProject("pg-service", "Development") - .WithArgs("-f", "net8.0") - .WithEndpoint(endpointName: "https", (e) => e.Port = 7834) - .WithEndpoint(endpointName: "http", (e) => e.Port = 5834) - .WithEnvironment("ConnectionStrings__Trek", postgresDB) - .WithEnvironment("db-type", "postgresql") - .WithUrls((e) => - { - e.Urls.Clear(); - e.Urls.Add(new() { Url = "/swagger", DisplayText = "🔒Swagger", Endpoint = e.GetEndpoint("https") }); - e.Urls.Add(new() { Url = "/graphql", DisplayText = "🔒GraphQL", Endpoint = e.GetEndpoint("https") }); - }) - .WithHttpHealthCheck("/health") - .WaitFor(postgresDB) - .WithExplicitStart(); - -// BUG: Blocked due to https://github.com/dotnet/aspire/issues/10680 -// msSql.WithParentRelationship(mssqlService); - -// Note: A space is required here due to a parsing issue in the framework. Without the space, the parent relationship may not be established correctly. See related issue: https://github.com/dotnet/aspire/issues/10680 -// postgresDB.WithParentRelationship(pgService); - -builder.Build().Run(); diff --git a/src/apphost/Properties/launchSettings.json b/src/apphost/Properties/launchSettings.json deleted file mode 100644 index 2a5a9a359f..0000000000 --- a/src/apphost/Properties/launchSettings.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/launchsettings.json", - "profiles": { - "https": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "applicationUrl": "https://localhost:17047;http://localhost:15161", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development", - "DOTNET_ENVIRONMENT": "Development", - "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21213", - "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22145" - } - }, - "http": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "applicationUrl": "http://localhost:15161", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development", - "DOTNET_ENVIRONMENT": "Development", - "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19015", - "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20166" - } - } - } -} From 0df564d75c44cd72c07b43319fbb54668f0f97b4 Mon Sep 17 00:00:00 2001 From: Aniruddh Munde Date: Sun, 9 Nov 2025 18:19:16 -0800 Subject: [PATCH 09/12] Apply suggestion from @Aniruddh25 --- src/Aspire.AppHost/Properties/launchSettings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Aspire.AppHost/Properties/launchSettings.json b/src/Aspire.AppHost/Properties/launchSettings.json index ed07d15a0b..c26777c442 100644 --- a/src/Aspire.AppHost/Properties/launchSettings.json +++ b/src/Aspire.AppHost/Properties/launchSettings.json @@ -24,7 +24,7 @@ "dotnetRunMessages": true, "applicationUrl": "http://localhost:15161" }, - "aspire-sql": { + "aspire-mssql": { "commandName": "Project", "launchBrowser": true, "environmentVariables": { From 60aa0dc0990d840c63be7d3ffd498aa595d6caeb Mon Sep 17 00:00:00 2001 From: Aniruddh Munde Date: Sun, 9 Nov 2025 18:20:01 -0800 Subject: [PATCH 10/12] Apply suggestions from code review Consistent Database type naming --- src/Aspire.AppHost/AppHost.cs | 6 +++--- src/Aspire.AppHost/Properties/launchSettings.json | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Aspire.AppHost/AppHost.cs b/src/Aspire.AppHost/AppHost.cs index 597902e9f1..34218624ac 100644 --- a/src/Aspire.AppHost/AppHost.cs +++ b/src/Aspire.AppHost/AppHost.cs @@ -8,7 +8,7 @@ switch (aspireDB) { - case "sql": + case "mssql": var sqlScript = File.ReadAllText("./init-scripts/sql/create-database.sql"); IResourceBuilder? sqlDbContainer = null; @@ -48,7 +48,7 @@ } break; - case "postgres": + case "postgresql": var pgScript = File.ReadAllText("./init-scripts/pg/create-database-pg.sql"); IResourceBuilder? postgresDB = null; @@ -89,7 +89,7 @@ break; default: - throw new Exception("Please set the ASPIRE_DATABASE environment variable to either 'sql' or 'postgre'."); + throw new Exception("Please set the ASPIRE_DATABASE environment variable to either 'mssql' or 'postgresql'."); } builder.Build().Run(); diff --git a/src/Aspire.AppHost/Properties/launchSettings.json b/src/Aspire.AppHost/Properties/launchSettings.json index c26777c442..43a2673a34 100644 --- a/src/Aspire.AppHost/Properties/launchSettings.json +++ b/src/Aspire.AppHost/Properties/launchSettings.json @@ -32,13 +32,13 @@ "DOTNET_ENVIRONMENT": "Development", "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21213", "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22145", - "ASPIRE_DATABASE_TYPE": "sql", + "ASPIRE_DATABASE_TYPE": "mssql", "ASPIRE_DATABASE_CONNECTION_STRING": "" }, "dotnetRunMessages": true, "applicationUrl": "https://localhost:17047;http://localhost:15161" }, - "aspire-postgres": { + "aspire-postgresql": { "commandName": "Project", "launchBrowser": true, "environmentVariables": { @@ -46,7 +46,7 @@ "DOTNET_ENVIRONMENT": "Development", "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21213", "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22145", - "ASPIRE_DATABASE_TYPE": "postgres", + "ASPIRE_DATABASE_TYPE": "postgresql", "ASPIRE_DATABASE_CONNECTION_STRING": "" }, "dotnetRunMessages": true, From 93a0388a7cc1dace712fbbfd30c3377728ee09af Mon Sep 17 00:00:00 2001 From: Aniruddh Munde Date: Sun, 9 Nov 2025 19:08:44 -0800 Subject: [PATCH 11/12] Ignore NU1603 warnings in Aspire project --- src/Aspire.AppHost/Aspire.AppHost.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Aspire.AppHost/Aspire.AppHost.csproj b/src/Aspire.AppHost/Aspire.AppHost.csproj index 6bafa2aa61..96fadd0763 100644 --- a/src/Aspire.AppHost/Aspire.AppHost.csproj +++ b/src/Aspire.AppHost/Aspire.AppHost.csproj @@ -6,6 +6,7 @@ Exe net8.0 enable + NU1603 enable f08719fd-267f-459e-9980-77b1c52c8755 From f9d45b8e0ab64f1b74901f73c22e5199313c9a84 Mon Sep 17 00:00:00 2001 From: Aniruddh Munde Date: Sun, 9 Nov 2025 19:46:43 -0800 Subject: [PATCH 12/12] Avoid package downgrade with explicit dependency additions --- src/Directory.Packages.props | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 617f95f5f5..b0201f9b59 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -6,6 +6,7 @@ + @@ -32,6 +33,7 @@ +