-
Notifications
You must be signed in to change notification settings - Fork 480
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
Conversation
Thanks for this! Can you please log an issue that represents this work? |
Of course, I created the issue #1307 |
Triggered package migration for the Oracle EF NuGet package to unblock the build. |
@@ -0,0 +1,24 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the .Database
suffix? The NuGet package from Oracle does not have this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to follow the existing pattern of other EF components where we have Aspire.X.EntityFrameworkCore.Y where:
X is the company/project
Y is the product
Oracle calls its product Oracle Database, so I followed this pattern to leave it open for other Oracle products that may support EntityFramework.
Aspire.Oracle.EntityFrameworkCore.Database
Aspire.Microsoft.EntityFrameworkCore.Cosmos
Aspire.Microsoft.EntityFrameworkCore.SqlServer
Aspire.Npgsql.EntityFrameworkCore.PostgreSQL
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. I'm happy with that as a justification as long as @eerhardt is happy as the czar of Aspire components ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The naming pattern we use is in
aspire/src/Components/README.md
Lines 27 to 30 in 23e168d
## Naming | |
- Each component's name must have the prefix `Aspire.`. | |
- When component is built around `ABC` client library, it should contain the client library name in its name. Example: `Aspire.ABC`. Where the technology has a particular casing we have preferred that: for example `Aspire.RabbitMQ` rather than `Aspire.RabbitMq`. |
This should be called Aspire.Oracle.EntityFrameworkCore
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@eerhardt PTAL for the component side of this? |
@andrevlins we need APIs for the AppModel side of things are you planning on adding this? There isn't much point having a component API surface without the corresponding AppModel APIs :) Take a look at the following for inspiration: |
Yes I was doing this in another PR #1004 |
/// </summary> | ||
/// <param name="name">The name of the resource.</param> | ||
/// <param name="connectionString">The Oracle Database connection string.</param> | ||
public class OracleDatabaseConnectionResource(string name, string? connectionString) : Resource(name), IOracleDatabaseResource |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can remove this type and its associated extension method. We've opted not to have XYZConnection resource types for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Yep, we made some changes to try and clarify a few things. You don't need the Oracle connection type anymore - with have a WithReference(ConnectionString) extension method for that kind of thing. You'll need to add The Apologies for the shifting API underneath you we are still shifting things around a bit. If we can get this change in though, it means that when we do future API changes we have to keep this up to date ;) |
Thank you very much for the explanations, I believe I made all the adaptations mentioned.
No problem! It's been great to follow the evolution of this project. |
...Aspire.Oracle.EntityFrameworkCore.Database/Aspire.Oracle.EntityFrameworkCore.Database.csproj
Outdated
Show resolved
Hide resolved
...Aspire.Oracle.EntityFrameworkCore.Database/Aspire.Oracle.EntityFrameworkCore.Database.csproj
Outdated
Show resolved
Hide resolved
...omponents/Aspire.Oracle.EntityFrameworkCore.Database/AspireOracleEFCoreDatabaseExtensions.cs
Outdated
Show resolved
Hide resolved
src/Components/Aspire.Oracle.EntityFrameworkCore.Database/README.md
Outdated
Show resolved
Hide resolved
tests/testproject/TestProject.IntegrationServiceA/TestProject.IntegrationServiceA.csproj
Outdated
Show resolved
Hide resolved
@@ -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); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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"); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
src/Components/Aspire.Oracle.EntityFrameworkCore/ConfigurationSchema.json
Show resolved
Hide resolved
[Theory] | ||
[InlineData(true)] | ||
[InlineData(false)] | ||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "Required to verify pooling without touching DB")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you move this to a #pragma
only around the code that needs it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is getting pretty close. Thanks for this work @andrevlins.
@@ -248,3 +248,30 @@ Aspire.StackExchange.Redis.OutputCaching: | |||
- Everything from `Aspire.StackExchange.Redis` plus: | |||
- Log categories: | |||
- "Microsoft.AspNetCore.OutputCaching.StackExchangeRedis" | |||
|
|||
Aspire.Oracle.EntityFrameworkCore: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(nit) Can you keep these are alphabetically ordered?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course, I didn't understand the ordering, sorry.
builder.AddOracleDatabaseDbContext<MyDbContext>("orcl", settings => settings.HealthChecks = false); | ||
``` | ||
|
||
## AppHost extensions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should also have a code snippet for the code to call AddOracleDatabaseDbContext
in the service project.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
/// <summary> | ||
/// <para>Gets or sets the maximum number of retry attempts.</para> | ||
/// <value> | ||
/// The default is 6. | ||
/// Set it to 0 to disable the retry mechanism. | ||
/// </value> | ||
/// </summary> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// <summary> | |
/// <para>Gets or sets the maximum number of retry attempts.</para> | |
/// <value> | |
/// The default is 6. | |
/// Set it to 0 to disable the retry mechanism. | |
/// </value> | |
/// </summary> | |
/// <summary> | |
/// <para>Gets or sets the maximum number of retry attempts.</para> | |
/// <para>Default value is 6, set it to 0 to disable the retry mechanism.</para> | |
/// </summary> |
value
isn't a valid element in summary. Repeated elsewhere. See
Lines 25 to 37 in bc220e3
/// <summary> | |
/// <para>Gets or sets the maximum number of retry attempts.</para> | |
/// <para>Default value is 6, set it to 0 to disable the retry mechanism.</para> | |
/// </summary> | |
public int MaxRetryCount { get; set; } = 6; | |
/// <summary> | |
/// Gets or sets a boolean value that indicates whether the database health check is enabled or not. | |
/// </summary> | |
/// <value> | |
/// The default value is <see langword="true"/>. | |
/// </value> | |
public bool HealthChecks { get; set; } = true; |
for the latest format.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All right
"Aspire": { | ||
"Oracle": { | ||
"EntityFrameworkCore": { | ||
"Database": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is out-dated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -8,13 +8,15 @@ | |||
builder.AddNpgsqlDataSource("postgresdb"); | |||
builder.AddRabbitMQ("rabbitmqcontainer"); | |||
builder.AddMongoDBClient("mymongodb"); | |||
builder.AddOracleClient("freepdb1"); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
app.MapGet("/oracledatabase/verify", VerifyOracleDatabaseAsync); | ||
} | ||
|
||
private static async Task<IResult> VerifyOracleDatabaseAsync(OracleConnection connection) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be
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.
I think we should merge this once preview 2 is out the door. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few more comments to fix up, and then I think this will be good to merge.
Thanks again for the contribution!
tests/Aspire.Hosting.Tests/Oracle/OracleDatabaseFunctionalTests.cs
Outdated
Show resolved
Hide resolved
@eerhardt I will update the pr with the new updates to solve the build problems |
Ready |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great. Thanks @andrevlins for the contribution!
No description provided.