feat: initialize mini api skeleton
This commit is contained in:
5
src/Api/Directory.Build.props
Normal file
5
src/Api/Directory.Build.props
Normal file
@@ -0,0 +1,5 @@
|
||||
<Project>
|
||||
<ItemGroup>
|
||||
<Using Include="Asp.Versioning" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,30 @@
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using TakeoutSaaS.Application.App.Mini.Bootstrap;
|
||||
using TakeoutSaaS.Shared.Abstractions.Results;
|
||||
using TakeoutSaaS.Shared.Web.Api;
|
||||
|
||||
namespace TakeoutSaaS.MiniApi.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// 小程序端启动引导接口。
|
||||
/// </summary>
|
||||
[ApiVersion("1.0")]
|
||||
[Route("api/mini/v{version:apiVersion}/bootstrap")]
|
||||
public sealed class BootstrapController(ISender sender) : BaseApiController
|
||||
{
|
||||
/// <summary>
|
||||
/// 返回当前服务基础能力与运行环境信息。
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
/// <returns>引导信息。</returns>
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(typeof(ApiResponse<MiniBootstrapResponse>), StatusCodes.Status200OK)]
|
||||
public async Task<ApiResponse<MiniBootstrapResponse>> GetAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await sender.Send(new GetMiniBootstrapQuery(), cancellationToken);
|
||||
return ApiResponse<MiniBootstrapResponse>.Ok(response);
|
||||
}
|
||||
}
|
||||
33
src/Api/TakeoutSaaS.MiniApi/Controllers/HealthController.cs
Normal file
33
src/Api/TakeoutSaaS.MiniApi/Controllers/HealthController.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using TakeoutSaaS.Shared.Abstractions.Results;
|
||||
using TakeoutSaaS.Shared.Web.Api;
|
||||
|
||||
namespace TakeoutSaaS.MiniApi.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// 小程序端健康检查。
|
||||
/// </summary>
|
||||
[ApiVersion("1.0")]
|
||||
[Route("api/mini/v{version:apiVersion}/health")]
|
||||
public sealed class HealthController : BaseApiController
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取服务健康状态。
|
||||
/// </summary>
|
||||
/// <returns>健康状态。</returns>
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
|
||||
public ApiResponse<object> Get()
|
||||
{
|
||||
var payload = new
|
||||
{
|
||||
status = "OK",
|
||||
service = "TakeoutSaaS.MiniApi",
|
||||
time = DateTime.UtcNow
|
||||
};
|
||||
|
||||
return ApiResponse<object>.Ok(payload);
|
||||
}
|
||||
}
|
||||
6
src/Api/TakeoutSaaS.MiniApi/Dockerfile
Normal file
6
src/Api/TakeoutSaaS.MiniApi/Dockerfile
Normal file
@@ -0,0 +1,6 @@
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:10.0
|
||||
WORKDIR /app
|
||||
COPY publish/ .
|
||||
EXPOSE 7803
|
||||
ENV ASPNETCORE_URLS=http://+:7803
|
||||
ENTRYPOINT ["dotnet", "TakeoutSaaS.MiniApi.dll"]
|
||||
148
src/Api/TakeoutSaaS.MiniApi/Program.cs
Normal file
148
src/Api/TakeoutSaaS.MiniApi/Program.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
using Microsoft.AspNetCore.Cors.Infrastructure;
|
||||
using Microsoft.Extensions.Options;
|
||||
using OpenTelemetry.Metrics;
|
||||
using OpenTelemetry.Resources;
|
||||
using OpenTelemetry.Trace;
|
||||
using Serilog;
|
||||
using TakeoutSaaS.Application.App.Extensions;
|
||||
using TakeoutSaaS.Infrastructure.App.Extensions;
|
||||
using TakeoutSaaS.Module.Tenancy.Extensions;
|
||||
using TakeoutSaaS.Shared.Abstractions.Ids;
|
||||
using TakeoutSaaS.Shared.Web.Extensions;
|
||||
using TakeoutSaaS.Shared.Web.Swagger;
|
||||
using TakeoutSaaS.Shared.Kernel.Ids;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
const string logTemplate = "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {Level:u3}] [TraceId:{TraceId}] [SpanId:{SpanId}] [Service:{Service}] {SourceContext} {Message:lj}{NewLine}{Exception}";
|
||||
var isDevelopment = builder.Environment.IsDevelopment();
|
||||
|
||||
builder.Host.UseSerilog((_, _, configuration) =>
|
||||
{
|
||||
configuration
|
||||
.Enrich.FromLogContext()
|
||||
.Enrich.WithProperty("Service", "TakeoutSaaS.MiniApi")
|
||||
.WriteTo.Console(outputTemplate: logTemplate)
|
||||
.WriteTo.File(
|
||||
"logs/mini-api-.log",
|
||||
rollingInterval: RollingInterval.Day,
|
||||
retainedFileCountLimit: 7,
|
||||
shared: true,
|
||||
outputTemplate: logTemplate);
|
||||
});
|
||||
|
||||
builder.Services.AddSharedWebCore();
|
||||
if (isDevelopment)
|
||||
{
|
||||
builder.Services.AddSharedSwagger(options =>
|
||||
{
|
||||
options.Title = "外卖SaaS - 小程序端";
|
||||
options.Description = "小程序 API 文档";
|
||||
options.EnableAuthorization = false;
|
||||
});
|
||||
}
|
||||
|
||||
builder.Services.AddAppInfrastructure(builder.Configuration);
|
||||
builder.Services.AddAppApplication();
|
||||
builder.Services.AddTenantResolution(builder.Configuration);
|
||||
builder.Services.AddHealthChecks();
|
||||
builder.Services.AddOptions<IdGeneratorOptions>()
|
||||
.Bind(builder.Configuration.GetSection(IdGeneratorOptions.SectionName))
|
||||
.ValidateDataAnnotations();
|
||||
builder.Services.AddSingleton<IIdGenerator>(provider =>
|
||||
{
|
||||
var options = provider.GetRequiredService<IOptions<IdGeneratorOptions>>().Value;
|
||||
return new SnowflakeIdGenerator(options.WorkerId, options.DatacenterId);
|
||||
});
|
||||
|
||||
var otelSection = builder.Configuration.GetSection("Otel");
|
||||
var otelEndpoint = otelSection.GetValue<string>("Endpoint");
|
||||
var useConsoleExporter = otelSection.GetValue<bool?>("UseConsoleExporter") ?? isDevelopment;
|
||||
builder.Services.AddOpenTelemetry()
|
||||
.ConfigureResource(resource => resource.AddService(
|
||||
serviceName: "TakeoutSaaS.MiniApi",
|
||||
serviceVersion: "1.0.0",
|
||||
serviceInstanceId: Environment.MachineName))
|
||||
.WithTracing(tracing =>
|
||||
{
|
||||
tracing
|
||||
.SetSampler(new ParentBasedSampler(new AlwaysOnSampler()))
|
||||
.AddAspNetCoreInstrumentation()
|
||||
.AddHttpClientInstrumentation();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(otelEndpoint))
|
||||
{
|
||||
tracing.AddOtlpExporter(exporter => exporter.Endpoint = new Uri(otelEndpoint));
|
||||
}
|
||||
|
||||
if (useConsoleExporter)
|
||||
{
|
||||
tracing.AddConsoleExporter();
|
||||
}
|
||||
})
|
||||
.WithMetrics(metrics =>
|
||||
{
|
||||
metrics
|
||||
.AddAspNetCoreInstrumentation()
|
||||
.AddHttpClientInstrumentation()
|
||||
.AddRuntimeInstrumentation()
|
||||
.AddPrometheusExporter();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(otelEndpoint))
|
||||
{
|
||||
metrics.AddOtlpExporter(exporter => exporter.Endpoint = new Uri(otelEndpoint));
|
||||
}
|
||||
|
||||
if (useConsoleExporter)
|
||||
{
|
||||
metrics.AddConsoleExporter();
|
||||
}
|
||||
});
|
||||
|
||||
var miniOrigins = ResolveCorsOrigins(builder.Configuration, "Cors:Mini");
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("MiniApiCors", policy =>
|
||||
{
|
||||
ConfigureCorsPolicy(policy, miniOrigins);
|
||||
});
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
app.UseCors("MiniApiCors");
|
||||
app.UseTenantResolution();
|
||||
app.UseSharedWebCore();
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSharedSwagger();
|
||||
}
|
||||
|
||||
app.MapHealthChecks("/healthz");
|
||||
app.MapPrometheusScrapingEndpoint();
|
||||
app.MapControllers();
|
||||
app.Run();
|
||||
|
||||
static string[] ResolveCorsOrigins(IConfiguration configuration, string sectionKey)
|
||||
{
|
||||
var origins = configuration.GetSection(sectionKey).Get<string[]>();
|
||||
return origins?
|
||||
.Where(origin => !string.IsNullOrWhiteSpace(origin))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray() ?? [];
|
||||
}
|
||||
|
||||
static void ConfigureCorsPolicy(CorsPolicyBuilder policy, string[] origins)
|
||||
{
|
||||
if (origins.Length == 0)
|
||||
{
|
||||
policy.AllowAnyOrigin();
|
||||
}
|
||||
else
|
||||
{
|
||||
policy.WithOrigins(origins);
|
||||
}
|
||||
|
||||
policy
|
||||
.AllowAnyHeader()
|
||||
.AllowAnyMethod();
|
||||
}
|
||||
14
src/Api/TakeoutSaaS.MiniApi/Properties/launchSettings.json
Normal file
14
src/Api/TakeoutSaaS.MiniApi/Properties/launchSettings.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"TakeoutSaaS.MiniApi": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "api/docs",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "http://localhost:2683"
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/Api/TakeoutSaaS.MiniApi/TakeoutSaaS.MiniApi.csproj
Normal file
28
src/Api/TakeoutSaaS.MiniApi/TakeoutSaaS.MiniApi.csproj
Normal file
@@ -0,0 +1,28 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<DockerfileContext>../../..</DockerfileContext>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="10.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
|
||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.14.0" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.14.0" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.14.0" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.14.0" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.14.0" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.14.0" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.14.0-beta.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\TakeoutSaaS.BuildingBlocks\src\Core\TakeoutSaaS.Shared.Kernel\TakeoutSaaS.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\..\TakeoutSaaS.BuildingBlocks\src\Core\TakeoutSaaS.Shared.Web\TakeoutSaaS.Shared.Web.csproj" />
|
||||
<ProjectReference Include="..\..\Application\TakeoutSaaS.Application\TakeoutSaaS.Application.csproj" />
|
||||
<ProjectReference Include="..\..\Infrastructure\TakeoutSaaS.Infrastructure\TakeoutSaaS.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\..\Modules\TakeoutSaaS.Module.Tenancy\TakeoutSaaS.Module.Tenancy.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
9
src/Api/TakeoutSaaS.MiniApi/appsettings.Development.json
Normal file
9
src/Api/TakeoutSaaS.MiniApi/appsettings.Development.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"Cors": {
|
||||
"Mini": []
|
||||
},
|
||||
"Otel": {
|
||||
"Endpoint": "",
|
||||
"UseConsoleExporter": true
|
||||
}
|
||||
}
|
||||
9
src/Api/TakeoutSaaS.MiniApi/appsettings.Production.json
Normal file
9
src/Api/TakeoutSaaS.MiniApi/appsettings.Production.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"Cors": {
|
||||
"Mini": []
|
||||
},
|
||||
"Otel": {
|
||||
"Endpoint": "",
|
||||
"UseConsoleExporter": false
|
||||
}
|
||||
}
|
||||
23
src/Api/TakeoutSaaS.MiniApi/appsettings.json
Normal file
23
src/Api/TakeoutSaaS.MiniApi/appsettings.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"AllowedHosts": "*",
|
||||
"IdGenerator": {
|
||||
"WorkerId": 0,
|
||||
"DatacenterId": 0
|
||||
},
|
||||
"Tenancy": {
|
||||
"TenantIdHeaderName": "X-Tenant-Id",
|
||||
"TenantCodeHeaderName": "X-Tenant-Code",
|
||||
"IgnoredPaths": [
|
||||
"/healthz",
|
||||
"/api/mini/v1/health"
|
||||
],
|
||||
"ThrowIfUnresolved": false
|
||||
},
|
||||
"Cors": {
|
||||
"Mini": []
|
||||
},
|
||||
"Otel": {
|
||||
"Endpoint": "",
|
||||
"UseConsoleExporter": false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user