♻️ Extract the Storage service to DysonNetwork.Drive microservice

This commit is contained in:
2025-07-06 17:29:26 +08:00
parent 6a3d04af3d
commit 14b79f16f4
71 changed files with 2629 additions and 346 deletions

View File

@ -0,0 +1,193 @@
using System;
using System.IO;
using System.Text.Json.Serialization;
using DysonNetwork.Drive.Data;
using DysonNetwork.Drive.Extensions;
using DysonNetwork.Drive.Interfaces;
using DysonNetwork.Drive.Models;
using DysonNetwork.Drive.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using NodaTime;
using Npgsql;
var builder = WebApplication.CreateBuilder(args);
// Add configuration
var configuration = builder.Configuration;
// Add services to the container.
builder.Services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
});
// Add NodaTime
builder.Services.AddSingleton<IClock>(SystemClock.Instance);
// Add database context
builder.Services.AddDbContext<AppDatabase>((serviceProvider, options) =>
{
var connectionString = configuration.GetConnectionString("DefaultConnection");
if (string.IsNullOrEmpty(connectionString))
{
throw new InvalidOperationException("Database connection string 'DefaultConnection' not found.");
}
options.UseNpgsql(
connectionString,
npgsqlOptions =>
{
npgsqlOptions.UseNodaTime();
npgsqlOptions.MigrationsAssembly(typeof(Program).Assembly.FullName);
});
options.UseSnakeCaseNamingConvention();
});
// Register services
builder.Services.AddScoped<IFileService, FileService>();
builder.Services.AddScoped<IFileReferenceService, FileReferenceService>();
// Configure CORS
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
// Configure JWT Authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = configuration["Jwt:Authority"];
options.Audience = configuration["Jwt:Audience"];
options.RequireHttpsMetadata = !builder.Environment.IsDevelopment();
});
// Configure Swagger
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Title = "DysonNetwork.Drive API",
Version = "v1",
Description = "API for managing files and file references in the Dyson Network",
Contact = new OpenApiContact
{
Name = "Dyson Network Team",
Email = "support@dyson.network"
}
});
// Include XML comments for API documentation
var xmlFile = $"{typeof(Program).Assembly.GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
if (File.Exists(xmlPath))
{
c.IncludeXmlComments(xmlPath);
}
// Configure JWT Bearer Authentication for Swagger
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer"
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Scheme = "oauth2",
Name = "Bearer",
In = ParameterLocation.Header,
},
Array.Empty<string>()
}
});
});
// Configure HTTP client for external services
builder.Services.AddHttpClient();
// Add health checks
builder.Services.AddHealthChecks()
.AddDbContextCheck<AppDatabase>();
// Add logging
builder.Services.AddLogging(configure => configure.AddConsole().AddDebug());
// Build the application
var app = builder.Build();
// Configure the HTTP request pipeline
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "DysonNetwork.Drive API v1");
c.RoutePrefix = "swagger";
});
}
// Apply database migrations
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var dbContext = services.GetRequiredService<AppDatabase>();
if (dbContext.Database.IsNpgsql())
{
await dbContext.Database.MigrateAsync();
app.Logger.LogInformation("Database migrations applied successfully.");
}
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred while applying database migrations.");
throw;
}
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.MapHealthChecks("/health");
app.Logger.LogInformation("Starting DysonNetwork.Drive application...");
await app.RunAsync();