Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Aspire.sln
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ParameterEndToEnd.AppHost",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ParameterEndToEnd.ApiService", "playground\ParameterEndToEnd\ParameterEndToEnd.ApiService\ParameterEndToEnd.ApiService.csproj", "{FD63D574-8512-421D-B7FC-310AFA974361}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "mysql", "mysql", "{621991F1-854A-4743-835B-10CAF11A0CFF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MySqlDb.AppHost", "Playground\mysql\MySqlDb.AppHost\MySqlDb.AppHost.csproj", "{7E2AD00B-60E0-46C2-8640-7217D678F312}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MySql.ApiService", "playground\mysql\MySql.ApiService\MySql.ApiService.csproj", "{F699F3AD-2AD9-454B-BA40-82AC3D6250FE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -599,6 +605,14 @@ Global
{FD63D574-8512-421D-B7FC-310AFA974361}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FD63D574-8512-421D-B7FC-310AFA974361}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FD63D574-8512-421D-B7FC-310AFA974361}.Release|Any CPU.Build.0 = Release|Any CPU
{7E2AD00B-60E0-46C2-8640-7217D678F312}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7E2AD00B-60E0-46C2-8640-7217D678F312}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7E2AD00B-60E0-46C2-8640-7217D678F312}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7E2AD00B-60E0-46C2-8640-7217D678F312}.Release|Any CPU.Build.0 = Release|Any CPU
{F699F3AD-2AD9-454B-BA40-82AC3D6250FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F699F3AD-2AD9-454B-BA40-82AC3D6250FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F699F3AD-2AD9-454B-BA40-82AC3D6250FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F699F3AD-2AD9-454B-BA40-82AC3D6250FE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -705,6 +719,9 @@ Global
{F1387494-34DE-4B31-B587-699B2E9A20CA} = {D173887B-AF42-4576-B9C1-96B9E9B3D9C0}
{54B66163-016D-4122-9364-409AB61BC36B} = {F1387494-34DE-4B31-B587-699B2E9A20CA}
{FD63D574-8512-421D-B7FC-310AFA974361} = {F1387494-34DE-4B31-B587-699B2E9A20CA}
{621991F1-854A-4743-835B-10CAF11A0CFF} = {D173887B-AF42-4576-B9C1-96B9E9B3D9C0}
{7E2AD00B-60E0-46C2-8640-7217D678F312} = {621991F1-854A-4743-835B-10CAF11A0CFF}
{F699F3AD-2AD9-454B-BA40-82AC3D6250FE} = {621991F1-854A-4743-835B-10CAF11A0CFF}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6DCEDFEC-988E-4CB3-B45B-191EB5086E0C}
Expand Down
22 changes: 22 additions & 0 deletions playground/mysql/MySql.ApiService/MySql.ApiService.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization>
<NoWarn>$(NoWarn);CS8002</NoWarn><!-- Dapper packages are not signed -->
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Dapper" />
<PackageReference Include="Swashbuckle.AspNetCore" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\Components\Aspire.Microsoft.Data.SqlClient\Aspire.Microsoft.Data.SqlClient.csproj" />
<ProjectReference Include="..\..\..\src\Components\Aspire.MySqlConnector\Aspire.MySqlConnector.csproj" />
<ProjectReference Include="..\..\Playground.ServiceDefaults\Playground.ServiceDefaults.csproj" />
</ItemGroup>

</Project>
26 changes: 26 additions & 0 deletions playground/mysql/MySql.ApiService/MySql.ApiService.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@HostAddress = http://localhost:5168

GET {{HostAddress}}/catalog/
Accept: application/json

###

GET {{HostAddress}}/catalog/1
Accept: application/json

###

POST {{HostAddress}}/catalog/
Content-Type: application/json

{
"name": "New Catalog Item",
"description": "New Catalog Description",
"price": 23.55
}

###
DELETE {{HostAddress}}/catalog/4
Accept: application/json

###
76 changes: 76 additions & 0 deletions playground/mysql/MySql.ApiService/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Dapper;
using MySqlConnector;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.AddServiceDefaults();

builder.Services.AddProblemDetails();
builder.AddMySqlDataSource("Catalog");

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.MapGet("/catalog", async (MySqlConnection db) =>
{
const string sql = """
SELECT Id, Name, Description, Price
FROM catalog
""";

return await db.QueryAsync<CatalogItem>(sql);
});

app.MapGet("/catalog/{id}", async (int id, MySqlConnection db) =>
{
const string sql = """
SELECT Id, Name, Description, Price
FROM catalog
WHERE Id = @id
""";

return await db.QueryFirstOrDefaultAsync<CatalogItem>(sql, new { id }) is { } item
? Results.Ok(item)
: Results.NotFound();
});

app.MapPost("/catalog", async (CatalogItem item, MySqlConnection db) =>
{
const string sql = """
INSERT INTO catalog (Name, Description, Price)
VALUES (@Name, @Description, @Price);
SELECT LAST_INSERT_ID();
""";

var id = await db.ExecuteScalarAsync<int>(sql, item);
return Results.Created($"/catalog/{id}", id);
});

app.MapDelete("/catalog/{id}", async (int id, MySqlConnection db) =>
{
const string sql = """
DELETE FROM catalog
WHERE Id = @id
""";

var rows = await db.ExecuteAsync(sql, new { id });
return rows > 0 ? Results.NoContent() : Results.NotFound();
});

app.Run();

public record CatalogItem(int Id, string Name, string Description, decimal Price);
41 changes: 41 additions & 0 deletions playground/mysql/MySql.ApiService/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:49646",
"sslPort": 44383
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5168",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7203;http://localhost:5168",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
9 changes: 9 additions & 0 deletions playground/mysql/MySql.ApiService/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
25 changes: 25 additions & 0 deletions playground/mysql/MySql.ApiService/data/init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
-- MySql init script

-- NOTE: MySql database and table names are case-sensitive on non-Windows platforms!
-- Column names are always case-insensitive.

-- Create the Catalog table
CREATE TABLE IF NOT EXISTS `catalog`
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`description` varchar(255) NOT NULL,
`price` DECIMAL(18,2) NOT NULL,
PRIMARY KEY (`id`)
);

-- Insert some sample data into the Catalog table only if the table is empty
INSERT INTO catalog (name, description, price)
SELECT *
FROM (
SELECT '.NET Bot Black Hoodie', 'This hoodie will keep you warm while looking cool and representing .NET!', 19.5 UNION ALL
SELECT '.NET Black & White Mug', 'The perfect place to keep your favorite beverage while you code.', 8.5 UNION ALL
SELECT 'Prism White T-Shirt', "It's a t-shirt, it's white, and it can be yours.", 12
) data
-- This clause ensures the rows are only inserted if the table is empty
WHERE NOT EXISTS (SELECT NULL FROM catalog)
8 changes: 8 additions & 0 deletions playground/mysql/MySqlDb.AppHost/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project>

<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />

<!-- NOTE: This line is only required because we are using P2P references, not NuGet. It will not exist in real apps. -->
<Import Project="../../../src/Aspire.Hosting/build/Aspire.Hosting.props" />

</Project>
9 changes: 9 additions & 0 deletions playground/mysql/MySqlDb.AppHost/Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project>

<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.targets', '$(MSBuildThisFileDirectory)../'))" />

<!-- NOTE: These lines are only required because we are using P2P references, not NuGet. They will not exist in real apps. -->
<Import Project="..\..\..\src\Aspire.Hosting\build\Aspire.Hosting.targets" />
<Import Project="..\..\..\src\Aspire.Hosting.Sdk\SDK\Sdk.targets" />

</Project>
22 changes: 22 additions & 0 deletions playground/mysql/MySqlDb.AppHost/MySqlDb.AppHost.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireHost>true</IsAspireHost>
</PropertyGroup>

<ItemGroup>
<Compile Include="$(SharedDir)KnownResourceNames.cs" Link="KnownResourceNames.cs" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\Aspire.Dashboard\Aspire.Dashboard.csproj" />
<ProjectReference Include="..\..\..\src\Aspire.Hosting.Azure\Aspire.Hosting.Azure.csproj" IsAspireProjectResource="false" />
<ProjectReference Include="..\..\..\src\Aspire.Hosting\Aspire.Hosting.csproj" IsAspireProjectResource="false" />
<ProjectReference Include="..\MySql.ApiService\MySql.ApiService.csproj" />
</ItemGroup>

</Project>
16 changes: 16 additions & 0 deletions playground/mysql/MySqlDb.AppHost/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

var builder = DistributedApplication.CreateBuilder(args);

var catalogDbName = "catalog"; // MySql database & table names are case-sensitive on non-Windows.
var catalogDb = builder.AddMySqlContainer("mysql")
.WithEnvironment("MYSQL_DATABASE", catalogDbName)
.WithVolumeMount("../MySql.ApiService/data", "/docker-entrypoint-initdb.d", VolumeMountType.Bind)
.WithPhpMyAdmin()
.AddDatabase(catalogDbName);

builder.AddProject<Projects.MySql_ApiService>("apiservice")
.WithReference(catalogDb);

builder.Build().Run();
16 changes: 16 additions & 0 deletions playground/mysql/MySqlDb.AppHost/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:15224",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:16160"
}
}
}
}
8 changes: 8 additions & 0 deletions playground/mysql/MySqlDb.AppHost/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
9 changes: 9 additions & 0 deletions playground/mysql/MySqlDb.AppHost/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Aspire.Hosting.Dcp": "Warning"
}
}
}
30 changes: 30 additions & 0 deletions src/Aspire.Hosting/MySql/MySqlBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

using System.Net.Sockets;
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Lifecycle;
using Aspire.Hosting.MySql;
using Aspire.Hosting.Publishing;

namespace Aspire.Hosting;
Expand Down Expand Up @@ -73,6 +75,34 @@ public static IResourceBuilder<MySqlDatabaseResource> AddDatabase(this IResource
.WithManifestPublishingCallback(context => WriteMySqlDatabaseToManifest(context, mySqlDatabase));
}

/// <summary>
/// Adds a phpMyAdmin administration and development platform for MySql to the application model.
/// </summary>
/// <param name="builder">The MySql server resource builder.</param>
/// <param name="hostPort">The host port for the application ui.</param>
/// <param name="containerName">The name of the container (Optional).</param>
/// <returns>A reference to the <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<T> WithPhpMyAdmin<T>(this IResourceBuilder<T> builder, int? hostPort = null, string? containerName = null) where T : IMySqlParentResource
{
if (builder.ApplicationBuilder.Resources.OfType<PhpMyAdminContainerResource>().Any())
{
return builder;
}

builder.ApplicationBuilder.Services.TryAddLifecycleHook<PhpMyAdminConfigWriterHook>();

containerName ??= $"{builder.Resource.Name}-phpmyadmin";

var phpMyAdminContainer = new PhpMyAdminContainerResource(containerName);
builder.ApplicationBuilder.AddResource(phpMyAdminContainer)
.WithAnnotation(new ContainerImageAnnotation { Image = "phpmyadmin", Tag = "latest" })
.WithHttpEndpoint(containerPort: 80, hostPort: hostPort, name: containerName)
.WithVolumeMount(Path.GetTempFileName(), "/etc/phpmyadmin/config.user.inc.php")
.ExcludeFromManifest();

return builder;
}

private static void WriteMySqlContainerToManifest(ManifestPublishingContext context)
{
context.Writer.WriteString("type", "mysql.server.v0");
Expand Down
Loading