Initial commit
This commit is contained in:
+27
@@ -0,0 +1,27 @@
|
||||
using TriunniaLabs.Arch.Sample.Aspire.AppHost;
|
||||
|
||||
var builder = DistributedApplication.CreateBuilder(args);
|
||||
|
||||
// Sql Server: One server hosting all databases for an all-in-one setup
|
||||
var sqlServer = builder.AddSampleSqlServer(); // http://host.docker.internal:51000
|
||||
|
||||
// Control Panel: Start here. Run the solution, which will start Aspire. Go to http://localhost:50000 in your browser to access the Control Panel.
|
||||
// In the Control Panel, create your application and set up the Application Api.
|
||||
// Copy its encrypted settings to both ApplicationApiSetup.cs and appsettings.json in the Sample Server, then uncomment it here.
|
||||
// Run the health check on the Application Api from the Control Panel. Repeat for all other Apis, including your app.
|
||||
builder.AddControlPanel(sqlServer); // http://host.docker.internal:50000
|
||||
|
||||
// Arch Apis: Pick which ones you need for your application. Uncomment only once they have been set up in the Control Panel. Application Api is required.
|
||||
// builder.AddApplicationApi(sqlServer); // http://host.docker.internal:50001
|
||||
// builder.AddKeysApi(sqlServer); // http://host.docker.internal:50002
|
||||
// builder.AddTokensApi(sqlServer); // http://host.docker.internal:50003
|
||||
// builder.AddEmailApi(sqlServer); // http://host.docker.internal:50004
|
||||
// builder.AddUsersApi(sqlServer); // http://host.docker.internal:50005
|
||||
// builder.AddCommentsApi(sqlServer); // http://host.docker.internal:50006
|
||||
// builder.AddEntityApi(sqlServer); // http://host.docker.internal:50007
|
||||
// builder.AddFilesApi(); // http://host.docker.internal:50008
|
||||
|
||||
// Your Application: Uncomment once you have set up your application in the Control Panel. It will run on port 50009.
|
||||
// builder.AddProject("SampleServer", "..\\..\\TriunniaLabs.Arch.Sample.Server\\TriunniaLabs.Arch.Sample.Server.csproj");
|
||||
|
||||
builder.Build().Run();
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:17209;http://localhost:15193",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"DOTNET_ENVIRONMENT": "Development",
|
||||
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21057",
|
||||
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22051"
|
||||
}
|
||||
},
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://localhost:15240",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"DOTNET_ENVIRONMENT": "Development",
|
||||
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19042",
|
||||
"ASPIRE_DASHBOARD_MCP_ENDPOINT_URL": "http://localhost:18273",
|
||||
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20197"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
namespace TriunniaLabs.Arch.Sample.Aspire.AppHost
|
||||
{
|
||||
internal static class ApplicationApiSetup
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a resource for the Application Api on port 50001.
|
||||
/// </summary>
|
||||
/// <param name="builder">Reference to the application builder.</param>
|
||||
/// <param name="sqlServer">Reference to the Sql Server resource.</param>
|
||||
public static void AddApplicationApi(this IDistributedApplicationBuilder builder, IResourceBuilder<SqlServerServerResource> sqlServer)
|
||||
{
|
||||
var applicationApiDb = sqlServer.AddDatabase("ApplicationApiDb");
|
||||
var applicationApi = builder.AddContainer("ApplicationApi", "gitea.triunnialabs.com/triunnialabs/arch-application-api", "0.9.8")
|
||||
.WithEndpoint(50001, 8080, isProxied: false, name: "http")
|
||||
.WithEndpoint("http", e => e.TargetHost = "0.0.0.0")
|
||||
|
||||
// Obtain the values for these fields from the Control Panel
|
||||
.WithEnvironment("Microservice__Name", "")
|
||||
.WithEnvironment("Microservice__EnvelopePassword", "")
|
||||
.WithEnvironment("Microservice__EnableDiagnostics", "true") // Set to false in production deployments
|
||||
.WithEnvironment("Microservice__Application__Url", "")
|
||||
.WithEnvironment("Microservice__Application__ApplicationId", "")
|
||||
.WithEnvironment("Microservice__Application__ApiKey", "")
|
||||
.WithEnvironment("Microservice__Application__EnvelopePassword", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__HmacSha512HashKey", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionPassword", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionSalt", "")
|
||||
.WithEnvironment("SqlServer__ConnectionString", "")
|
||||
.WithEnvironment("SqlServer__ReadOnlyConnectionString", "")
|
||||
.WithEnvironment("YubiHsm__ConnectorUrl", "")
|
||||
.WithEnvironment("Guardian__AccessToken", "")
|
||||
.WithEnvironment("Guardian__BootstrapKeyObjectId", "")
|
||||
|
||||
// Api will write log and other files to this relatiove source folder
|
||||
.WithBindMount("..\\..\\..\\data\\ApplicationApi", "/opt/triunnialabs/arch/application-api")
|
||||
|
||||
.WithReference(applicationApiDb)
|
||||
.WaitFor(applicationApiDb);
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
namespace TriunniaLabs.Arch.Sample.Aspire.AppHost
|
||||
{
|
||||
internal static class ComomentsApiSetup
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a resource for the Comments Api on port 50006.
|
||||
/// </summary>
|
||||
/// <param name="builder">Reference to the application builder.</param>
|
||||
/// <param name="sqlServer">Reference to the Sql Server resource.</param>
|
||||
public static void AddCommentsApi(this IDistributedApplicationBuilder builder, IResourceBuilder<SqlServerServerResource> sqlServer)
|
||||
{
|
||||
var commentsApiDb = sqlServer.AddDatabase("CommentsApiDb");
|
||||
builder.AddContainer("CommentsApi", "gitea.triunnialabs.com/triunnialabs/arch-comments-api", "0.1.0")
|
||||
.WithEndpoint(50006, 8080, isProxied: false, name: "http")
|
||||
.WithEndpoint("http", e => e.TargetHost = "0.0.0.0")
|
||||
|
||||
// Obtain the values for these fields from the Control Panel
|
||||
.WithEnvironment("Microservice__Name", "")
|
||||
.WithEnvironment("Microservice__EnvelopePassword", "")
|
||||
.WithEnvironment("Microservice__EnableDiagnostics", "true") // Set to false in production deployments
|
||||
.WithEnvironment("Microservice__Application__Url", "")
|
||||
.WithEnvironment("Microservice__Application__ApplicationId", "")
|
||||
.WithEnvironment("Microservice__Application__ApiKey", "")
|
||||
.WithEnvironment("Microservice__Application__EnvelopePassword", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__HmacSha512HashKey", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionPassword", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionSalt", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionIterations", "")
|
||||
.WithEnvironment("SqlServer__ConnectionString", "")
|
||||
.WithEnvironment("SqlServer__ReadOnlyConnectionString", "")
|
||||
|
||||
// Api will write log and other files to this relatiove source folder
|
||||
.WithBindMount("..\\..\\..\\data\\CommentsApi", "/opt/triunnialabs/arch/comments-api")
|
||||
|
||||
.WithReference(commentsApiDb)
|
||||
.WaitFor(commentsApiDb);
|
||||
}
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
namespace TriunniaLabs.Arch.Sample.Aspire.AppHost
|
||||
{
|
||||
internal static class EmailApiSetup
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a resource for the Email Api on port 50004.
|
||||
/// </summary>
|
||||
/// <param name="builder">Reference to the application builder.</param>
|
||||
/// <param name="sqlServer">Reference to the Sql Server resource.</param>
|
||||
public static void AddEmailApi(this IDistributedApplicationBuilder builder, IResourceBuilder<SqlServerServerResource> sqlServer)
|
||||
{
|
||||
var emailApiDb = sqlServer.AddDatabase("EmailApiDb");
|
||||
builder.AddContainer("EmailApi", "gitea.triunnialabs.com/triunnialabs/arch-email-api", "0.2.2")
|
||||
.WithEndpoint(50004, 8080, isProxied: false, name: "http")
|
||||
.WithEndpoint("http", e => e.TargetHost = "0.0.0.0")
|
||||
|
||||
// Obtain the values for these fields from the Control Panel
|
||||
.WithEnvironment("Microservice__Name", "")
|
||||
.WithEnvironment("Microservice__EnvelopePassword", "")
|
||||
.WithEnvironment("Microservice__EnableDiagnostics", "true") // Set to false in production deployments
|
||||
.WithEnvironment("Microservice__Application__Url", "")
|
||||
.WithEnvironment("Microservice__Application__ApplicationId", "")
|
||||
.WithEnvironment("Microservice__Application__ApiKey", "")
|
||||
.WithEnvironment("Microservice__Application__EnvelopePassword", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__HmacSha512HashKey", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionPassword", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionSalt", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionIterations", "")
|
||||
.WithEnvironment("SqlServer__ConnectionString", "")
|
||||
.WithEnvironment("SqlServer__ReadOnlyConnectionString", "")
|
||||
.WithEnvironment("Postmark__ServerToken", "") // Postmark is required for sending emails
|
||||
.WithEnvironment("Postmark__WebhookAuthUser", "") // Other providers to be added as demand requires (SendGrid, etc.)
|
||||
.WithEnvironment("Postmark__WebhookAuthPassword", "")
|
||||
.WithEnvironment("TokensApi__Url", "") // Email Api requires Tokens Api
|
||||
.WithEnvironment("TokensApi__ApplicationId", "")
|
||||
.WithEnvironment("TokensApi__ApiKey", "")
|
||||
.WithEnvironment("TokensApi__EnvelopePassword", "")
|
||||
|
||||
// Api will write log and other files to this relatiove source folder
|
||||
.WithBindMount("..\\..\\..\\data\\EmailApi", "/opt/triunnialabs/arch/email-api")
|
||||
|
||||
.WithReference(emailApiDb)
|
||||
.WaitFor(emailApiDb);
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
namespace TriunniaLabs.Arch.Sample.Aspire.AppHost
|
||||
{
|
||||
internal static class EntityApiSetup
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a resource for the Entity Api on port 50007.
|
||||
/// </summary>
|
||||
/// <param name="builder">Reference to the application builder.</param>
|
||||
/// <param name="sqlServer">Reference to the Sql Server resource.</param>
|
||||
public static void AddEntityApi(this IDistributedApplicationBuilder builder, IResourceBuilder<SqlServerServerResource> sqlServer)
|
||||
{
|
||||
var entityApiDb = sqlServer.AddDatabase("EntityApiDb");
|
||||
builder.AddContainer("EntityApi", "gitea.triunnialabs.com/triunnialabs/arch-entity-api", "0.1.4")
|
||||
.WithEndpoint(50007, 8080, isProxied: false, name: "http")
|
||||
.WithEndpoint("http", e => e.TargetHost = "0.0.0.0")
|
||||
|
||||
// Obtain the values for these fields from the Control Panel
|
||||
.WithEnvironment("Microservice__Name", "")
|
||||
.WithEnvironment("Microservice__EnvelopePassword", "")
|
||||
.WithEnvironment("Microservice__EnableDiagnostics", "true") // Set to false in production deployments
|
||||
.WithEnvironment("Microservice__Application__Url", "")
|
||||
.WithEnvironment("Microservice__Application__ApplicationId", "")
|
||||
.WithEnvironment("Microservice__Application__ApiKey", "")
|
||||
.WithEnvironment("Microservice__Application__EnvelopePassword", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__HmacSha512HashKey", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionPassword", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionSalt", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionIterations", "")
|
||||
.WithEnvironment("SqlServer__ConnectionString", "")
|
||||
.WithEnvironment("SqlServer__ReadOnlyConnectionString", "")
|
||||
|
||||
// Api will write log and other files to this relatiove source folder
|
||||
.WithBindMount("..\\..\\..\\data\\EntityApi", "/opt/triunnialabs/arch/entity-api")
|
||||
|
||||
.WithReference(entityApiDb)
|
||||
.WaitFor(entityApiDb);
|
||||
}
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
namespace TriunniaLabs.Arch.Sample.Aspire.AppHost
|
||||
{
|
||||
internal static class FilesApiSetup
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a resource for the Files Api on port 50008.
|
||||
/// </summary>
|
||||
/// <param name="builder">Reference to the application builder.</param>
|
||||
public static void AddFilesApi(this IDistributedApplicationBuilder builder)
|
||||
{
|
||||
builder.AddContainer("FilesApi", "gitea.triunnialabs.com/triunnialabs/arch-files-api", "0.1.3")
|
||||
.WithEndpoint(50008, 8080, isProxied: false, name: "http")
|
||||
.WithEndpoint("http", e => e.TargetHost = "0.0.0.0")
|
||||
|
||||
// Obtain the values for these fields from the Control Panel
|
||||
.WithEnvironment("Microservice__Name", "")
|
||||
.WithEnvironment("Microservice__EnvelopePassword", "")
|
||||
.WithEnvironment("Microservice__EnableDiagnostics", "true") // Set to false in production deployments
|
||||
.WithEnvironment("Microservice__Application__Url", "")
|
||||
.WithEnvironment("Microservice__Application__ApplicationId", "")
|
||||
.WithEnvironment("Microservice__Application__ApiKey", "")
|
||||
.WithEnvironment("Microservice__Application__EnvelopePassword", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__HmacSha512HashKey", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionPassword", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionSalt", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionIterations", "")
|
||||
.WithEnvironment("FilesApi__DataPath", "")
|
||||
|
||||
// Api will write log and other files to this relatiove source folder
|
||||
.WithBindMount("..\\..\\..\\data\\FilesApi", "/opt/triunnialabs/arch/files-api");
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
namespace TriunniaLabs.Arch.Sample.Aspire.AppHost
|
||||
{
|
||||
internal static class KeysApiSetup
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a resource for the Keys Api on port 50002.
|
||||
/// </summary>
|
||||
/// <param name="builder">Reference to the application builder.</param>
|
||||
/// <param name="sqlServer">Reference to the Sql Server resource.</param>
|
||||
public static void AddKeysApi(this IDistributedApplicationBuilder builder, IResourceBuilder<SqlServerServerResource> sqlServer)
|
||||
{
|
||||
var keysApiDb = sqlServer.AddDatabase("KeysApiDb");
|
||||
builder.AddContainer("KeysApi", "gitea.triunnialabs.com/triunnialabs/arch-keys-api", "0.1.17")
|
||||
.WithEndpoint(50002, 8080, isProxied: false, name: "http")
|
||||
.WithEndpoint("http", e => e.TargetHost = "0.0.0.0")
|
||||
|
||||
// Obtain the values for these fields from the Control Panel
|
||||
.WithEnvironment("Microservice__Name", "")
|
||||
.WithEnvironment("Microservice__EnvelopePassword", "")
|
||||
.WithEnvironment("Microservice__EnableDiagnostics", "true") // Set to false in production deployments
|
||||
.WithEnvironment("Microservice__Application__Url", "")
|
||||
.WithEnvironment("Microservice__Application__ApplicationId", "")
|
||||
.WithEnvironment("Microservice__Application__ApiKey", "")
|
||||
.WithEnvironment("Microservice__Application__EnvelopePassword", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__HmacSha512HashKey", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionPassword", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionSalt", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionIterations", "")
|
||||
.WithEnvironment("SqlServer__ConnectionString", "")
|
||||
.WithEnvironment("SqlServer__ReadOnlyConnectionString", "")
|
||||
|
||||
// Api will write log and other files to this relatiove source folder
|
||||
.WithBindMount("..\\..\\..\\data\\KeysApi", "/opt/triunnialabs/arch/keys-api")
|
||||
|
||||
.WithReference(keysApiDb)
|
||||
.WaitFor(keysApiDb);
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
namespace TriunniaLabs.Arch.Sample.Aspire.AppHost
|
||||
{
|
||||
internal static class TokensApiSetup
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a resource for the Tokens Api on port 50003.
|
||||
/// </summary>
|
||||
/// <param name="builder">Reference to the application builder.</param>
|
||||
/// <param name="sqlServer">Reference to the Sql Server resource.</param>
|
||||
public static void AddTokensApi(this IDistributedApplicationBuilder builder, IResourceBuilder<SqlServerServerResource> sqlServer)
|
||||
{
|
||||
var tokensApiDb = sqlServer.AddDatabase("TokensApiDb");
|
||||
builder.AddContainer("TokensApi", "gitea.triunnialabs.com/triunnialabs/arch-tokens-api", "0.3.1")
|
||||
.WithEndpoint(50003, 8080, isProxied: false, name: "http")
|
||||
.WithEndpoint("http", e => e.TargetHost = "0.0.0.0")
|
||||
|
||||
// Obtain the values for these fields from the Control Panel
|
||||
.WithEnvironment("Microservice__Name", "")
|
||||
.WithEnvironment("Microservice__EnvelopePassword", "")
|
||||
.WithEnvironment("Microservice__EnableDiagnostics", "true") // Set to false in production deployments
|
||||
.WithEnvironment("Microservice__Application__Url", "")
|
||||
.WithEnvironment("Microservice__Application__ApplicationId", "")
|
||||
.WithEnvironment("Microservice__Application__ApiKey", "")
|
||||
.WithEnvironment("Microservice__Application__EnvelopePassword", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__HmacSha512HashKey", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionPassword", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionSalt", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionIterations", "")
|
||||
.WithEnvironment("SqlServer__ConnectionString", "")
|
||||
.WithEnvironment("SqlServer__ReadOnlyConnectionString", "")
|
||||
|
||||
// Api will write log and other files to this relatiove source folder
|
||||
.WithBindMount("..\\..\\..\\data\\TokensApi", "/opt/triunnialabs/arch/tokens-api")
|
||||
|
||||
.WithReference(tokensApiDb)
|
||||
.WaitFor(tokensApiDb);
|
||||
}
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
namespace TriunniaLabs.Arch.Sample.Aspire.AppHost
|
||||
{
|
||||
internal static class UsersApiSetup
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a resource for the Users Api on port 50005.
|
||||
/// </summary>
|
||||
/// <param name="builder">Reference to the application builder.</param>
|
||||
/// <param name="sqlServer">Reference to the Sql Server resource.</param>
|
||||
public static void AddUsersApi(this IDistributedApplicationBuilder builder, IResourceBuilder<SqlServerServerResource> sqlServer)
|
||||
{
|
||||
var usersApiDb = sqlServer.AddDatabase("UsersApiDb");
|
||||
builder.AddContainer("UsersApi", "gitea.triunnialabs.com/triunnialabs/arch-users-api", "0.2.44")
|
||||
.WithEndpoint(50005, 8080, isProxied: false, name: "http")
|
||||
.WithEndpoint("http", e => e.TargetHost = "0.0.0.0")
|
||||
|
||||
// Obtain the values for these fields from the Control Panel
|
||||
.WithEnvironment("Microservice__Name", "")
|
||||
.WithEnvironment("Microservice__EnvelopePassword", "")
|
||||
.WithEnvironment("Microservice__EnableDiagnostics", "true") // Set to false in production deployments
|
||||
.WithEnvironment("Microservice__Application__Url", "")
|
||||
.WithEnvironment("Microservice__Application__ApplicationId", "")
|
||||
.WithEnvironment("Microservice__Application__ApiKey", "")
|
||||
.WithEnvironment("Microservice__Application__EnvelopePassword", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__HmacSha512HashKey", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionPassword", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionSalt", "")
|
||||
.WithEnvironment("Microservice__ProtectedMemory__AesEncryptionIterations", "")
|
||||
.WithEnvironment("SqlServer__ConnectionString", "")
|
||||
.WithEnvironment("SqlServer__ReadOnlyConnectionString", "")
|
||||
.WithEnvironment("TokensApi__Url", "") // Users Api requires Tokens Api
|
||||
.WithEnvironment("TokensApi__ApplicationId", "")
|
||||
.WithEnvironment("TokensApi__ApiKey", "")
|
||||
.WithEnvironment("TokensApi__EnvelopePassword", "")
|
||||
.WithEnvironment("KeysApi__Url", "") // Users Api requires Keys Api
|
||||
.WithEnvironment("KeysApi__ApplicationId", "")
|
||||
.WithEnvironment("KeysApi__ApiKey", "")
|
||||
.WithEnvironment("KeysApi__EnvelopePassword", "")
|
||||
.WithEnvironment("EmailApi__Url", "") // Users Api requires Email Api
|
||||
.WithEnvironment("EmailApi__ApplicationId", "")
|
||||
.WithEnvironment("EmailApi__ApiKey", "")
|
||||
.WithEnvironment("EmailApi__EnvelopePassword", "")
|
||||
.WithEnvironment("UsersApi__AuthenticationScheme", "MySampleAuthScheme") // Set to your authentication scheme name (appears in browser)
|
||||
|
||||
// Api will write log and other files to this relatiove source folder
|
||||
.WithBindMount("..\\..\\..\\data\\UsersApi", "/opt/triunnialabs/arch/users-api")
|
||||
|
||||
.WithReference(usersApiDb)
|
||||
.WaitFor(usersApiDb);
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
namespace TriunniaLabs.Arch.Sample.Aspire.AppHost
|
||||
{
|
||||
internal static class ControlPanelSetup
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a resource for the Control Panel on port 50000.
|
||||
/// </summary>
|
||||
/// <param name="builder">Reference to the application builder.</param>
|
||||
/// <param name="sqlServer">Reference to the Sql Server resource.</param>
|
||||
public static void AddControlPanel(this IDistributedApplicationBuilder builder, IResourceBuilder<SqlServerServerResource> sqlServer)
|
||||
{
|
||||
var controlPanelDb = sqlServer.AddDatabase("ControlPanelDb");
|
||||
builder.AddContainer("ControlPanel", "gitea.triunnialabs.com/triunnialabs/arch-control-panel", "0.0.22")
|
||||
.WithEndpoint(50000, 8080, isProxied: false, name: "http")
|
||||
.WithEndpoint("http", e => e.TargetHost = "0.0.0.0")
|
||||
.WithEnvironment("ControlPanel__DataPath", "/opt/triunnialabs/arch/controlpanel")
|
||||
.WithBindMount("..\\..\\..\\data\\ControlPanel", "/opt/triunnialabs/arch/controlpanel")
|
||||
.WithReference(controlPanelDb)
|
||||
.WaitFor(controlPanelDb);
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
namespace TriunniaLabs.Arch.Sample.Aspire.AppHost
|
||||
{
|
||||
internal static class SqlServerSetup
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a resource for a Sql Server database on port 51000.
|
||||
/// </summary>
|
||||
/// <param name="builder">Reference to the application builder.</param>
|
||||
/// <returns>
|
||||
/// Returns the Sql Server resource.
|
||||
/// </returns>
|
||||
public static IResourceBuilder<SqlServerServerResource> AddSampleSqlServer(this IDistributedApplicationBuilder builder)
|
||||
{
|
||||
var password = builder.AddParameter("password", "p@ssw0rd");
|
||||
var sqlServer = builder.AddSqlServer("Sample-SqlServer", password, 51000)
|
||||
.WithDataVolume("Sample-SqlServer-Data")
|
||||
.WithEndpoint("tcp", e => { e.IsProxied = false; });
|
||||
return sqlServer;
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Aspire.AppHost.Sdk/13.2.4">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<UserSecretsId>eaa9faa0-83e2-49df-8f34-af7c4906a005</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Aspire.Hosting.AppHost" Version="13.3.5" />
|
||||
<PackageReference Include="Aspire.Hosting.SqlServer" Version="13.3.5" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning",
|
||||
"Aspire.Hosting.Dcp": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.ServiceDiscovery;
|
||||
using OpenTelemetry;
|
||||
using OpenTelemetry.Metrics;
|
||||
using OpenTelemetry.Trace;
|
||||
|
||||
namespace Microsoft.Extensions.Hosting;
|
||||
|
||||
// Adds common Aspire services: service discovery, resilience, health checks, and OpenTelemetry.
|
||||
// This project should be referenced by each service project in your solution.
|
||||
// To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults
|
||||
public static class Extensions
|
||||
{
|
||||
private const string HealthEndpointPath = "/health";
|
||||
private const string AlivenessEndpointPath = "/alive";
|
||||
|
||||
public static TBuilder AddServiceDefaults<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
|
||||
{
|
||||
builder.ConfigureOpenTelemetry();
|
||||
|
||||
builder.AddDefaultHealthChecks();
|
||||
|
||||
builder.Services.AddServiceDiscovery();
|
||||
|
||||
builder.Services.ConfigureHttpClientDefaults(http =>
|
||||
{
|
||||
// Turn on resilience by default
|
||||
http.AddStandardResilienceHandler();
|
||||
|
||||
// Turn on service discovery by default
|
||||
http.AddServiceDiscovery();
|
||||
});
|
||||
|
||||
// Uncomment the following to restrict the allowed schemes for service discovery.
|
||||
// builder.Services.Configure<ServiceDiscoveryOptions>(options =>
|
||||
// {
|
||||
// options.AllowedSchemes = ["https"];
|
||||
// });
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static TBuilder ConfigureOpenTelemetry<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
|
||||
{
|
||||
builder.Logging.AddOpenTelemetry(logging =>
|
||||
{
|
||||
logging.IncludeFormattedMessage = true;
|
||||
logging.IncludeScopes = true;
|
||||
});
|
||||
|
||||
builder.Services.AddOpenTelemetry()
|
||||
.WithMetrics(metrics =>
|
||||
{
|
||||
metrics.AddAspNetCoreInstrumentation()
|
||||
.AddHttpClientInstrumentation()
|
||||
.AddRuntimeInstrumentation();
|
||||
})
|
||||
.WithTracing(tracing =>
|
||||
{
|
||||
tracing.AddSource(builder.Environment.ApplicationName)
|
||||
.AddAspNetCoreInstrumentation(tracing =>
|
||||
// Exclude health check requests from tracing
|
||||
tracing.Filter = context =>
|
||||
!context.Request.Path.StartsWithSegments(HealthEndpointPath)
|
||||
&& !context.Request.Path.StartsWithSegments(AlivenessEndpointPath)
|
||||
)
|
||||
// Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package)
|
||||
//.AddGrpcClientInstrumentation()
|
||||
.AddHttpClientInstrumentation();
|
||||
});
|
||||
|
||||
builder.AddOpenTelemetryExporters();
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static TBuilder AddOpenTelemetryExporters<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
|
||||
{
|
||||
var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
|
||||
|
||||
if (useOtlpExporter)
|
||||
{
|
||||
builder.Services.AddOpenTelemetry().UseOtlpExporter();
|
||||
}
|
||||
|
||||
// Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package)
|
||||
//if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]))
|
||||
//{
|
||||
// builder.Services.AddOpenTelemetry()
|
||||
// .UseAzureMonitor();
|
||||
//}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static TBuilder AddDefaultHealthChecks<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
|
||||
{
|
||||
builder.Services.AddHealthChecks()
|
||||
// Add a default liveness check to ensure app is responsive
|
||||
.AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static WebApplication MapDefaultEndpoints(this WebApplication app)
|
||||
{
|
||||
// Adding health checks endpoints to applications in non-development environments has security implications.
|
||||
// See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
// All health checks must pass for app to be considered ready to accept traffic after starting
|
||||
app.MapHealthChecks(HealthEndpointPath);
|
||||
|
||||
// Only health checks tagged with the "live" tag must pass for app to be considered alive
|
||||
app.MapHealthChecks(AlivenessEndpointPath, new HealthCheckOptions
|
||||
{
|
||||
Predicate = r => r.Tags.Contains("live")
|
||||
});
|
||||
}
|
||||
|
||||
return app;
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsAspireSharedProject>true</IsAspireSharedProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
|
||||
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="10.6.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="10.6.0" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.3" />
|
||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.15.3" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.2" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.15.1" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.15.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"appHost": {
|
||||
"path": "TriunniaLabs.Arch.Sample.Aspire.AppHost/TriunniaLabs.Arch.Sample.Aspire.AppHost.csproj"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
using MessagePack;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Security.Claims;
|
||||
using System.Text.Encodings.Web;
|
||||
using TriunniaLabs.Arch.Api.Users.Client;
|
||||
using TriunniaLabs.Arch.Microservice;
|
||||
using TriunniaLabs.Memory.Protected;
|
||||
|
||||
namespace TriunniaLabs.Arch.Sample.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// An authentication handler that validates a user's token/session.
|
||||
/// </summary>
|
||||
public class UserAuthenticationHandler : AuthenticationHandler<UserAuthenticationHandlerOptions>
|
||||
{
|
||||
// Services
|
||||
private readonly ILogger<UserAuthenticationHandler> _logger;
|
||||
private readonly UsersApiSettings _settings;
|
||||
private readonly IFormatterResolver _formatterResolver;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="options">Reference to the options class for this handler.</param>
|
||||
/// <param name="loggerFactory">Reference to the logger factory.</param>
|
||||
/// <param name="urlEncoder">Reference to the url encoder.</param>
|
||||
/// <param name="logger">Reference to the logger.</param>
|
||||
/// <param name="settings">Reference to the users api settings.</param>
|
||||
/// <param name="formatterResolver">Reference to the MessagePack formatter resolver.</param>
|
||||
public UserAuthenticationHandler(IOptionsMonitor<UserAuthenticationHandlerOptions> options, ILoggerFactory loggerFactory, UrlEncoder urlEncoder,
|
||||
ILogger<UserAuthenticationHandler> logger, IOptions<UsersApiSettings> settings,
|
||||
IFormatterResolver formatterResolver)
|
||||
: base(options, loggerFactory, urlEncoder)
|
||||
{
|
||||
_logger = logger;
|
||||
_settings = settings.Value;
|
||||
_formatterResolver = formatterResolver;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles token authentication.
|
||||
/// </summary>
|
||||
protected async override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
{
|
||||
using (_logger.ScopeWithMethod())
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Authenticate user...");
|
||||
|
||||
// Look for the authorization header
|
||||
if (Request.Headers.ContainsKey("Authorization") == false)
|
||||
{
|
||||
_logger.LogInformation("Not applicable: Authorization header not found.");
|
||||
return await Task.FromResult(AuthenticateResult.NoResult());
|
||||
}
|
||||
|
||||
// Get the authorization header
|
||||
var header = Request.Headers["Authorization"].ToString().Split(new string[] { " " }, System.StringSplitOptions.RemoveEmptyEntries);
|
||||
if (header.Length != 2)
|
||||
{
|
||||
_logger.LogInformation("Not applicable: Incorrect authentication scheme - header length.");
|
||||
return await Task.FromResult(AuthenticateResult.NoResult());
|
||||
}
|
||||
|
||||
// Verify that it is an appropriate header
|
||||
if (header[0] != _settings.AuthenticationScheme)
|
||||
{
|
||||
_logger.LogInformation("Not applicable: Incorrect authentication scheme - header name.");
|
||||
return await Task.FromResult(AuthenticateResult.NoResult());
|
||||
}
|
||||
|
||||
// Get the token
|
||||
if (string.IsNullOrEmpty(header[1]) == true)
|
||||
{
|
||||
_logger.LogInformation("Authentication failed: Invalid token.");
|
||||
return await Task.FromResult(AuthenticateResult.Fail("Invalid token.")).ConfigureAwait(false);
|
||||
}
|
||||
var relayProtector = ProtectedProtocol.RelayMessageProtector<string>(_formatterResolver);
|
||||
var token = relayProtector.Receive(header[1].Replace("\"", ""));
|
||||
if (token.IsEmpty)
|
||||
{
|
||||
_logger.LogInformation("Authentication failed: Invalid token.");
|
||||
return await Task.FromResult(AuthenticateResult.Fail("Invalid token.")).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// Token comes in Relay protected. Need to use Standard protected for ValidateSessionAsync.
|
||||
var standardProtector = ProtectedProtocol.StandardProtector<string>(_formatterResolver);
|
||||
token.Reconfigure(standardProtector);
|
||||
|
||||
// Validate the session using a fresh-scoped Users Api client so the standard-protected
|
||||
// auth header does not contaminate the shared _usersApiClient used by relay controllers.
|
||||
// Relay controllers that call unauthenticated Users Api endpoints (e.g. CheckEmail) must
|
||||
// not forward an auth header, otherwise the Users Api auth handler fails to relay-decrypt
|
||||
// the standard-protected token and returns 500.
|
||||
var ipAddress = Request.HttpContext.Connection?.RemoteIpAddress?.ToString() ?? "";
|
||||
var protectedIpAddress = ipAddress.AsProtected();
|
||||
using var validationScope = Context.RequestServices.CreateScope();
|
||||
var validationClient = validationScope.ServiceProvider.GetRequiredService<IUsersApiClient>();
|
||||
validationClient.SetAuthorizationHeader(token);
|
||||
validationClient.SetIpAddressOriginHeader(protectedIpAddress);
|
||||
var userId = await validationClient.ValidateSessionAsync(token, protectedIpAddress).ConfigureAwait(false);
|
||||
if (userId is null)
|
||||
{
|
||||
_logger.LogInformation("Authentication failed: Unauthorized.");
|
||||
return await Task.FromResult(AuthenticateResult.Fail("Unauthorized.")).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Token is valid and user is authenticated
|
||||
_logger.LogInformation("Authentication successful.");
|
||||
|
||||
// Generate a principal object for the user
|
||||
var claims = new[] { new Claim(ClaimTypes.NameIdentifier, userId.ToString()) };
|
||||
var identity = new ClaimsIdentity(claims, nameof(UserAuthenticationHandler));
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
|
||||
// Create an authentication ticket for the user.
|
||||
var ticket = new AuthenticationTicket(principal, Scheme.Name);
|
||||
|
||||
// Return a success code with the authentication ticket
|
||||
return await Task.FromResult(AuthenticateResult.Success(ticket)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, ex.Message);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
|
||||
namespace TriunniaLabs.Arch.Sample.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// An options class for the User Authentication Handler.
|
||||
/// </summary>
|
||||
public class UserAuthenticationHandlerOptions : AuthenticationSchemeOptions
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
|
||||
namespace TriunniaLabs.Arch.Sample.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// A health check to allow other services to check this service for uptime.
|
||||
/// </summary>
|
||||
public class HealthCheck : IHealthCheck
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks the health of the server to determine its condition.
|
||||
/// </summary>
|
||||
/// <param name="context">The context under which the health check is run.</param>
|
||||
/// <param name="cancellationToken">A cancellation to use </param>
|
||||
public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// Just return healthy as this is only an uptime check for now
|
||||
return Task.FromResult(HealthCheckResult.Healthy());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Net;
|
||||
|
||||
namespace TriunniaLabs.Arch.Sample.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// A middleware that specifies a dummy ip address for use with the test server.
|
||||
/// </summary>
|
||||
public class DummyIpAddressMiddleware : IMiddleware
|
||||
{
|
||||
/// <summary>
|
||||
/// Occurs when this middleware is invoked.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="HttpContext"/> for the current request.</param>
|
||||
/// <param name="next">The delegate representing the remaining middleware in the request pipeline.</param>
|
||||
/// <returns>A <see cref="Task"/> that represents the execution of this middleware.</returns>
|
||||
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
|
||||
{
|
||||
// Set localhost ip address
|
||||
context.Connection.RemoteIpAddress = IPAddress.Parse("::1");
|
||||
|
||||
// Pass control to the next middleware
|
||||
await next(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Reflection;
|
||||
using TriunniaLabs.Arch.Api.Comments.Client;
|
||||
using TriunniaLabs.Arch.Api.Email.Client;
|
||||
using TriunniaLabs.Arch.Api.Entity.Client;
|
||||
using TriunniaLabs.Arch.Api.Files.Client;
|
||||
using TriunniaLabs.Arch.Api.Keys.Client;
|
||||
using TriunniaLabs.Arch.Api.Tokens.Client;
|
||||
using TriunniaLabs.Arch.Api.Users.Client;
|
||||
using TriunniaLabs.Arch.Microservice;
|
||||
using TriunniaLabs.Arch.Relay.Email.Server;
|
||||
using TriunniaLabs.Arch.Relay.Users.Server;
|
||||
using TriunniaLabs.Arch.Sample.Server;
|
||||
using TriunniaLabs.Memory.Protected;
|
||||
|
||||
// Start the ASP.NET application builder
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
builder.Services.AddControllers();
|
||||
|
||||
// Triunnia Labs: Set up your application to use Arch and add any services it directly depends on
|
||||
builder.Host.UseTriunniaLabsMicroservice(EnvironmentType.Development);
|
||||
builder.Services.AddTriunniaLabsMicroservice(builder.Configuration);
|
||||
builder.Services.AddTriunniaLabsKeysApi(builder.Configuration, builder.Services.AddStandardMessagePackFormatters);
|
||||
builder.Services.AddTriunniaLabsTokensApi(builder.Configuration, builder.Services.AddStandardMessagePackFormatters);
|
||||
builder.Services.AddTriunniaLabsEmailApi(builder.Configuration, builder.Services.AddStandardMessagePackFormatters);
|
||||
builder.Services.AddTriunniaLabsUsersApi(builder.Configuration, builder.Services.AddStandardMessagePackFormatters);
|
||||
builder.Services.AddTriunniaLabsCommentsApi(builder.Configuration, builder.Services.AddStandardMessagePackFormatters);
|
||||
builder.Services.AddTriunniaLabsEntityApi(builder.Configuration, builder.Services.AddStandardMessagePackFormatters);
|
||||
builder.Services.AddTriunniaLabsFilesApi(builder.Configuration, builder.Services.AddStandardMessagePackFormatters);
|
||||
|
||||
// Configuration
|
||||
builder.Services.AddRouting(options => options.LowercaseUrls = true);
|
||||
|
||||
// Diagnostics: Add a diagnostics provider so you can debug your configuration from the Control Panel
|
||||
builder.Services.AddTransient<IDiagnosticConfigurationProvider, DiagnosicConfigurationProvider>();
|
||||
|
||||
// Converters: MessagePack is used for serialization within Arch and is part of the Protected Memory system.
|
||||
// You may need to add some converters for your application to function.
|
||||
builder.Services.AddKeyedSingleton<IByteArrayConverter<string>, MessagePackUntrustedByteArrayConverter<string>>("MessagePackUntrustedByteArrayConverter<System.String>");
|
||||
builder.Services.AddKeyedSingleton<IByteArrayConverter<string[]>, MessagePackUntrustedByteArrayConverter<string[]>>("MessagePackUntrustedByteArrayConverter<System.String[]>");
|
||||
builder.Services.AddKeyedSingleton<IByteArrayConverter<Guid>, MessagePackUntrustedByteArrayConverter<Guid>>("MessagePackUntrustedByteArrayConverter<System.Guid>");
|
||||
|
||||
// MessagePack Formatters: Any custom object or data type will need to be registered so that it can be handled by the Protected Memory system.
|
||||
// All of your app's request/response objects, DTOs, and models should be registered.
|
||||
builder.Services.AddStandardMessagePackFormatters(new[]
|
||||
{
|
||||
typeof(bool),
|
||||
typeof(bool?),
|
||||
typeof(char),
|
||||
typeof(DateTime),
|
||||
typeof(DateTime?)
|
||||
});
|
||||
|
||||
// Authentication
|
||||
var settings = builder.Services.BuildServiceProvider().GetRequiredService<IOptions<UsersApiSettings>>().Value;
|
||||
builder.Services.AddAuthentication(options => options.DefaultScheme = settings.AuthenticationScheme)
|
||||
.AddScheme<UserAuthenticationHandlerOptions, UserAuthenticationHandler>(settings.AuthenticationScheme, options => { })
|
||||
.AddScheme<ApplicationAuthenticationHandlerOptions, ApplicationAuthenticationHandler>(ArchConstants.ApplicationAuthenticationScheme, options => { });
|
||||
|
||||
// Controllers
|
||||
builder.Services.AddMvc()
|
||||
.AddApplicationPart(Assembly.GetExecutingAssembly()).AddControllersAsServices()
|
||||
.AddTriunniaLabsUsersApiRelay(builder.Services.AddStandardMessagePackFormatters)
|
||||
.AddTriunniaLabsEmailApiRelay();
|
||||
|
||||
// Health Checks
|
||||
builder.Services.AddHealthChecks().AddCheck<HealthCheck>("health-check");
|
||||
|
||||
// Middleware
|
||||
if (builder.Environment.IsDevelopment())
|
||||
builder.Services.AddSingleton<DummyIpAddressMiddleware>();
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Triunnia Labs
|
||||
app.UseTriunniaLabsMicroservice();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseMiddleware<DummyIpAddressMiddleware>();
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
else
|
||||
{
|
||||
app.UseExceptionHandler("/Error");
|
||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||
app.UseHsts();
|
||||
app.UseResponseCompression();
|
||||
}
|
||||
|
||||
// Https and Static Files
|
||||
app.UseHttpsRedirection();
|
||||
app.UseStaticFiles();
|
||||
|
||||
// Authentication, Routing, and Authorization
|
||||
app.UseAuthorization();
|
||||
app.UseRouting();
|
||||
app.UseAuthorization();
|
||||
|
||||
// Controllers and Routing
|
||||
app.MapControllers();
|
||||
app.MapHealthChecks("/diagnostics/health-check");
|
||||
|
||||
// Run the server
|
||||
app.Run();
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"TriunniaLabs.Arch.Sample.Server": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"dotnetRunMessages": true,
|
||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||
"applicationUrl": "http://localhost:50009;https://localhost:51009"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using TriunniaLabs.Arch.Api.Email.Client;
|
||||
using TriunniaLabs.Arch.Api.Entity.Client;
|
||||
using TriunniaLabs.Arch.Api.Files.Client;
|
||||
using TriunniaLabs.Arch.Api.Users.Client;
|
||||
using TriunniaLabs.Arch.Microservice;
|
||||
|
||||
namespace TriunniaLabs.Arch.Sample.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// A provider for supplying additional configuration information for the purpose of diagnostics.
|
||||
/// </summary>
|
||||
public class DiagnosicConfigurationProvider : IDiagnosticConfigurationProvider
|
||||
{
|
||||
// Data
|
||||
private readonly UsersApiSettings _usersApiSettings;
|
||||
private readonly EmailApiSettings _emailApiSettings;
|
||||
private readonly EntityApiSettings _entityApiSettings;
|
||||
private readonly FilesApiSettings _filesApiSettings;
|
||||
|
||||
// Services
|
||||
private readonly ILogger<DiagnosicConfigurationProvider> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="usersApiSettings">Reference to the Users Api setttings.</param>
|
||||
/// <param name="emailApiSettings">Reference to the Email Api setttings.</param>
|
||||
/// <param name="entityApiSettings">Reference to the Entity Api setttings.</param>
|
||||
/// <param name="filesApiSettings">Reference to the Files Api setttings.</param>
|
||||
/// <param name="logger">Reference to the logger.</param>
|
||||
public DiagnosicConfigurationProvider(IOptions<UsersApiSettings> usersApiSettings, IOptions<EmailApiSettings> emailApiSettings,
|
||||
IOptions<EntityApiSettings> entityApiSettings, IOptions<FilesApiSettings> filesApiSettings,
|
||||
ILogger<DiagnosicConfigurationProvider> logger)
|
||||
{
|
||||
_usersApiSettings = usersApiSettings?.Value ?? throw new ArgumentNullException(nameof(usersApiSettings));
|
||||
_emailApiSettings = emailApiSettings?.Value ?? throw new ArgumentNullException(nameof(emailApiSettings));
|
||||
_entityApiSettings = entityApiSettings?.Value ?? throw new ArgumentNullException(nameof(entityApiSettings));
|
||||
_filesApiSettings = filesApiSettings?.Value ?? throw new ArgumentNullException(nameof(filesApiSettings));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supplies custom settings used by the microservice to the diagnostic report.
|
||||
/// Call <see cref="DiagnosticSettingsResponse.AddSetting{T}(string, Memory.Protected.Protected{T}?)" /> to add each setting.
|
||||
/// </summary>
|
||||
/// <param name="report">The diagnostic report to configure.</param>
|
||||
public void SupplySettings(DiagnosticSettingsResponse report)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Add all additional protected configuration settings for your application here.
|
||||
// They will be reported to the Control Panel via its Diagnostics feature when EnableDiagnostics is true.
|
||||
|
||||
report.AddSetting("UsersApi.ApplicationId", _usersApiSettings.ApplicationId);
|
||||
report.AddSetting("UsersApi.Url", _usersApiSettings.Url);
|
||||
report.AddSetting("UsersApi.ApiKey", _usersApiSettings.ApiKey);
|
||||
report.AddSetting("UsersApi.EnvelopePassword", _usersApiSettings.EnvelopePassword);
|
||||
|
||||
report.AddSetting("EmailApi.ApplicationId", _emailApiSettings.ApplicationId);
|
||||
report.AddSetting("EmailApi.Url", _emailApiSettings.Url);
|
||||
report.AddSetting("EmailApi.ApiKey", _emailApiSettings.ApiKey);
|
||||
report.AddSetting("EmailApi.EnvelopePassword", _emailApiSettings.EnvelopePassword);
|
||||
|
||||
report.AddSetting("EntityApi.ApplicationId", _entityApiSettings.ApplicationId);
|
||||
report.AddSetting("EntityApi.Url", _entityApiSettings.Url);
|
||||
report.AddSetting("EntityApi.ApiKey", _entityApiSettings.ApiKey);
|
||||
report.AddSetting("EntityApi.EnvelopePassword", _entityApiSettings.EnvelopePassword);
|
||||
|
||||
report.AddSetting("FilesApi.ApplicationId", _filesApiSettings.ApplicationId);
|
||||
report.AddSetting("FilesApi.Url", _filesApiSettings.Url);
|
||||
report.AddSetting("FilesApi.ApiKey", _filesApiSettings.ApiKey);
|
||||
report.AddSetting("FilesApi.EnvelopePassword", _filesApiSettings.EnvelopePassword);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Unable to supply settings for configuration diagnostic.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="TriunniaLabs.Arch.Api.Comments.Client" Version="0.1.0" />
|
||||
<PackageReference Include="TriunniaLabs.Arch.Api.Email.Client" Version="0.2.2" />
|
||||
<PackageReference Include="TriunniaLabs.Arch.Api.Entity.Client" Version="0.1.4" />
|
||||
<PackageReference Include="TriunniaLabs.Arch.Api.Files.Client" Version="0.1.3" />
|
||||
<PackageReference Include="TriunniaLabs.Arch.Api.Keys.Client" Version="0.1.17" />
|
||||
<PackageReference Include="TriunniaLabs.Arch.Api.Tokens.Client" Version="0.3.1" />
|
||||
<PackageReference Include="TriunniaLabs.Arch.Api.Users.Client" Version="0.2.44" />
|
||||
<PackageReference Include="TriunniaLabs.Arch.Microservice" Version="0.9.8" />
|
||||
<PackageReference Include="TriunniaLabs.Arch.Relay.Email.Server" Version="0.2.2" />
|
||||
<PackageReference Include="TriunniaLabs.Arch.Relay.Users.Server" Version="0.2.44" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"Microservice": {
|
||||
"Name": "",
|
||||
"EnvelopePassword": "",
|
||||
"EnableDiagnostics": true,
|
||||
"Application": {
|
||||
"Url": "",
|
||||
"ApplicationId": "",
|
||||
"ApiKey": "",
|
||||
"EnvelopePassword": ""
|
||||
},
|
||||
"ProtectedMemory": {
|
||||
"HmacSha512HashKey": "",
|
||||
"AesEncryptionPassword": "",
|
||||
"AesEncryptionSalt": "",
|
||||
"AesEncryptionIterations": ""
|
||||
}
|
||||
},
|
||||
|
||||
"KeysApi": {
|
||||
"Url": "",
|
||||
"ApplicationId": "",
|
||||
"ApiKey": "",
|
||||
"EnvelopePassword": ""
|
||||
},
|
||||
|
||||
"TokensApi": {
|
||||
"Url": "",
|
||||
"ApplicationId": "",
|
||||
"ApiKey": "",
|
||||
"EnvelopePassword": ""
|
||||
},
|
||||
|
||||
"EmailApi": {
|
||||
"Url": "",
|
||||
"ApplicationId": "",
|
||||
"ApiKey": "",
|
||||
"EnvelopePassword": ""
|
||||
},
|
||||
|
||||
"UsersApi": {
|
||||
"Url": "",
|
||||
"ApplicationId": "",
|
||||
"ApiKey": "",
|
||||
"EnvelopePassword": "",
|
||||
"AuthenticationScheme": "MySampleAuthScheme"
|
||||
},
|
||||
|
||||
"CommentsApi": {
|
||||
"Url": "",
|
||||
"ApplicationId": "",
|
||||
"ApiKey": "",
|
||||
"EnvelopePassword": ""
|
||||
},
|
||||
|
||||
"EntityApi": {
|
||||
"Url": "",
|
||||
"ApplicationId": "",
|
||||
"ApiKey": "",
|
||||
"EnvelopePassword": ""
|
||||
},
|
||||
|
||||
"FilesApi": {
|
||||
"Url": "",
|
||||
"ApplicationId": "",
|
||||
"ApiKey": "",
|
||||
"EnvelopePassword": ""
|
||||
},
|
||||
|
||||
"Serilog": {
|
||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
|
||||
"MinimumLevel": {
|
||||
"Default": "Debug",
|
||||
"Override": {
|
||||
"Microsoft": "Warning",
|
||||
"System": "Warning"
|
||||
}
|
||||
},
|
||||
"WriteTo": [
|
||||
{
|
||||
"Name": "Console",
|
||||
"Args": {
|
||||
"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "File",
|
||||
"Args": {
|
||||
"path": "Logs/log-.txt",
|
||||
"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact",
|
||||
"rollingInterval": "Day",
|
||||
"retainedFileCountLimit": 7
|
||||
}
|
||||
}
|
||||
],
|
||||
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<Solution>
|
||||
<Project Path="TriunniaLabs.Arch.Sample.Aspire/TriunniaLabs.Arch.Sample.Aspire.AppHost/TriunniaLabs.Arch.Sample.Aspire.AppHost.csproj" Id="6cb44d36-37cb-47cb-b6dc-e3f1900b3eb5" />
|
||||
<Project Path="TriunniaLabs.Arch.Sample.Aspire/TriunniaLabs.Arch.Sample.Aspire.ServiceDefaults/TriunniaLabs.Arch.Sample.Aspire.ServiceDefaults.csproj" />
|
||||
<Project Path="TriunniaLabs.Arch.Sample.Server/TriunniaLabs.Arch.Sample.Server.csproj" />
|
||||
</Solution>
|
||||
Reference in New Issue
Block a user