Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Aspire Oracle EntityFrameworkCore Database component. #1295

Merged
merged 18 commits into from
Jan 3, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
4 changes: 2 additions & 2 deletions src/Aspire.Hosting/Oracle/OracleDatabaseBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static class OracleDatabaseBuilderExtensions
/// <returns>A reference to the <see cref="IResourceBuilder{OracleDatabaseContainerResource}"/>.</returns>
public static IResourceBuilder<OracleDatabaseContainerResource> AddOracleDatabaseContainer(this IDistributedApplicationBuilder builder, string name, int? port = null, string? password = null)
{
password = password ?? Guid.NewGuid().ToString("N");
password = password ?? Guid.NewGuid().ToString("N").Substring(0, 30);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should centralize this generated password logic into PasswordUtils @mitchdenny

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that it is different than SqlServer.

password = password ?? Guid.NewGuid().ToString("N") + Guid.NewGuid().ToString("N").ToUpper();

and MySql

password ??= Guid.NewGuid().ToString("N");

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably just come up with a decent password generator that we can use. What I did for SQL Server was half baked and really only appropriate for inner loop (which luckily is where it is used). I'd be happy to see this go in without change this password generation logic and instead see an issue created where we properly develop out PasswordUtils than can meet our various use cases (needs to be flexible enough to side step various limitations around what the containerized tool can used, and what we can escape in the connection string.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know an issue hasn't been created yet, but I saw this comment and opened a PR that might address it: #1469.

var oracleDatabaseContainer = new OracleDatabaseContainerResource(name, password);
return builder.AddResource(oracleDatabaseContainer)
.WithManifestPublishingCallback(context => WriteOracleDatabaseContainerResourceToManifest(context, oracleDatabaseContainer))
Expand All @@ -51,7 +51,7 @@ public static IResourceBuilder<OracleDatabaseContainerResource> AddOracleDatabas
/// <returns>A reference to the <see cref="IResourceBuilder{OracleDatabaseServerResource}"/>.</returns>
public static IResourceBuilder<OracleDatabaseServerResource> AddOracleDatabase(this IDistributedApplicationBuilder builder, string name)
{
var password = Guid.NewGuid().ToString("N");
var password = Guid.NewGuid().ToString("N").Substring(0, 30);
var oracleDatabaseServer = new OracleDatabaseServerResource(name, password);
return builder.AddResource(oracleDatabaseServer)
.WithManifestPublishingCallback(WriteOracleDatabaseContainerToManifest)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using Microsoft.Extensions.DependencyInjection;
using Xunit;

namespace Aspire.Hosting.Tests;
namespace Aspire.Hosting.Tests.Oracle;

public class AddOracleDatabaseTests
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.Hosting.Tests.Helpers;
using Xunit;

namespace Aspire.Hosting.Tests.Oracle;

[Collection("IntegrationServices")]
public class OracleDatabaseFunctionalTests
{
private readonly IntegrationServicesFixture _integrationServicesFixture;

public OracleDatabaseFunctionalTests(IntegrationServicesFixture integrationServicesFixture)
{
_integrationServicesFixture = integrationServicesFixture;
}

[LocalOnlyFact()]
public async Task VerifyOracleDatabaseWorks()
{
var testProgram = _integrationServicesFixture.TestProgram;
var client = _integrationServicesFixture.HttpClient;

using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1));

var response = await testProgram.IntegrationServiceABuilder!.HttpGetAsync(client, "http", "/oracledatabase/verify", cts.Token);

Assert.True(response.IsSuccessStatusCode);
eerhardt marked this conversation as resolved.
Show resolved Hide resolved
}
}
8 changes: 7 additions & 1 deletion tests/testproject/TestProject.AppHost/TestProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ private TestProgram(string[] args, Assembly assembly, bool includeIntegrationSer
var mysqlDbName = "mysqldb";
var postgresDbName = "postgresdb";
var mongoDbName = "mymongodb";
var oracleDbName = "freepdb1";

var sqlserverContainer = AppBuilder.AddSqlServerContainer("sqlservercontainer")
.AddDatabase(sqlserverDbName);
Expand All @@ -49,13 +50,16 @@ private TestProgram(string[] args, Assembly assembly, bool includeIntegrationSer
var rabbitmqContainer = AppBuilder.AddRabbitMQContainer("rabbitmqcontainer");
var mongodbContainer = AppBuilder.AddMongoDBContainer("mongodbcontainer")
.AddDatabase(mongoDbName);
var oracleDatabaseContainer = AppBuilder.AddOracleDatabaseContainer("oracledatabasecontainer")
.AddDatabase(oracleDbName);

var sqlserverAbstract = AppBuilder.AddSqlServerContainer("sqlserverabstract");
var mysqlAbstract = AppBuilder.AddMySqlContainer("mysqlabstract");
var redisAbstract = AppBuilder.AddRedisContainer("redisabstract");
var postgresAbstract = AppBuilder.AddPostgresContainer("postgresabstract");
var rabbitmqAbstract = AppBuilder.AddRabbitMQContainer("rabbitmqabstract");
var mongodbAbstract = AppBuilder.AddMongoDB("mongodbabstract");
var oracleDatabaseAbstract = AppBuilder.AddOracleDatabaseContainer("oracledatabaseabstract");

IntegrationServiceABuilder = AppBuilder.AddProject<Projects.IntegrationServiceA>("integrationservicea")
.WithReference(sqlserverContainer)
Expand All @@ -64,12 +68,14 @@ private TestProgram(string[] args, Assembly assembly, bool includeIntegrationSer
.WithReference(postgresContainer)
.WithReference(rabbitmqContainer)
.WithReference(mongodbContainer)
.WithReference(oracleDatabaseContainer)
.WithReference(sqlserverAbstract)
.WithReference(mysqlAbstract)
.WithReference(redisAbstract)
.WithReference(postgresAbstract)
.WithReference(rabbitmqAbstract)
.WithReference(mongodbAbstract);
.WithReference(mongodbAbstract)
.WithReference(oracleDatabaseAbstract);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Oracle.ManagedDataAccess.Client;

public static class OracleDatabaseExtensions
{
public static void MapOracleDatabaseApi(this WebApplication app)
{
app.MapGet("/oracledatabase/verify", VerifyOracleDatabaseAsync);
}

private static async Task<IResult> VerifyOracleDatabaseAsync(OracleConnection connection)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be

Suggested change
private static async Task<IResult> VerifyOracleDatabaseAsync(OracleConnection connection)
private static async Task<IResult> VerifyOracleDatabaseAsync(MyDbContext dbContext)

And then using the EF Component you are adding in this PR.

{
try
{
await connection.OpenAsync();

var command = connection.CreateCommand();
command.CommandText = $"SELECT 1 FROM DUAL";
var results = await command.ExecuteReaderAsync();

return results.HasRows ? Results.Ok("Success!") : Results.Problem("Failed");
}
catch (Exception e)
{
return Results.Problem(e.ToString());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Oracle.ManagedDataAccess.Client;

// This is a workaround while https://github.com/dotnet/aspire/pull/1004 is not merged.
public static class OracleManagedDataAccessExtensions
{
public static void AddOracleClient(this WebApplicationBuilder builder, string connectionName)
{
ArgumentNullException.ThrowIfNull(builder);

var connectionString = builder.Configuration.GetConnectionString(connectionName);
builder.Services.AddScoped(_ => new OracleConnection(connectionString));
}

public static void AddKeyedOracleClient(this WebApplicationBuilder builder, string connectionName)
{
ArgumentNullException.ThrowIfNull(builder);

var connectionString = builder.Configuration.GetConnectionString(connectionName);
builder.Services.AddKeyedSingleton(connectionName, (serviceProvider, _) => new OracleConnection(connectionString));
}
}
4 changes: 4 additions & 0 deletions tests/testproject/TestProject.IntegrationServiceA/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@
builder.AddNpgsqlDataSource("postgresdb");
builder.AddRabbitMQ("rabbitmqcontainer");
builder.AddMongoDBClient("mymongodb");
builder.AddOracleClient("freepdb1");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test program should be using the Oracle EF Component you are adding, not a workaround method and talking to an OracleConnection directly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. It makes perfect sense, I got a little lost here. Thank you for the explanation.


builder.AddKeyedSqlServerClient("sqlserverabstract");
builder.AddKeyedMySqlDataSource("mysqlabstract");
builder.AddKeyedRedis("redisabstract");
builder.AddKeyedNpgsqlDataSource("postgresabstract");
builder.AddKeyedRabbitMQ("rabbitmqabstract");
builder.AddKeyedMongoDBClient("mongodbabstract");
builder.AddKeyedOracleClient("oracledatabaseabstract");

var app = builder.Build();

Expand All @@ -36,4 +38,6 @@

app.MapRabbitMQApi();

app.MapOracleDatabaseApi();

app.Run();
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<ProjectReference Include="..\..\..\src\Components\Aspire.MongoDB.Driver\Aspire.MongoDB.Driver.csproj" />
<ProjectReference Include="..\..\..\src\Components\Aspire.MySqlConnector\Aspire.MySqlConnector.csproj" />
<ProjectReference Include="..\..\..\src\Components\Aspire.Npgsql\Aspire.Npgsql.csproj" />
<ProjectReference Include="..\..\..\src\Components\Aspire.Oracle.EntityFrameworkCore.Database\Aspire.Oracle.EntityFrameworkCore.Database.csproj" />
<ProjectReference Include="..\..\..\src\Components\Aspire.Oracle.EntityFrameworkCore\Aspire.Oracle.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\..\src\Components\Aspire.RabbitMQ.Client\Aspire.RabbitMQ.Client.csproj" />
<ProjectReference Include="..\..\..\src\Components\Aspire.StackExchange.Redis\Aspire.StackExchange.Redis.csproj" />
</ItemGroup>
Expand Down