Browse Source

Initial commit with .gitignore and project files

master
root 7 days ago
commit
acdc447bb4
  1. 45
      .gitignore
  2. 12
      CoreAgent.API/Configurations/api-versioning.json
  3. 30
      CoreAgent.API/Configurations/logger.json
  4. 17
      CoreAgent.API/Configurations/request-logging.Development.json
  5. 17
      CoreAgent.API/Configurations/request-logging.json
  6. 45
      CoreAgent.API/Controllers/WeatherForecastController.cs
  7. 28
      CoreAgent.API/CoreAgent.API.csproj
  8. 6
      CoreAgent.API/CoreAgent.API.http
  9. 67
      CoreAgent.API/Program.cs
  10. 41
      CoreAgent.API/Properties/launchSettings.json
  11. 118
      CoreAgent.API/Startup.cs
  12. 8
      CoreAgent.API/appsettings.Development.json
  13. 9
      CoreAgent.API/appsettings.json
  14. 98
      CoreAgent.API/logs/log-20250610.txt
  15. 9
      CoreAgent.Application/CoreAgent.Application.csproj
  16. 13
      CoreAgent.Domain/CoreAgent.Domain.csproj
  17. 14
      CoreAgent.Domain/Exceptions/NotFoundException.cs
  18. 17
      CoreAgent.Domain/Exceptions/ValidationException.cs
  19. 23
      CoreAgent.Domain/Models/ErrorResponse.cs
  20. 28
      CoreAgent.Infrastructure/CoreAgent.Infrastructure.csproj
  21. 13
      CoreAgent.Infrastructure/CoreAgent.Infrastructure.csproj.Backup.tmp
  22. 44
      CoreAgent.Infrastructure/Extensions/ApiVersioningExtensions.cs
  23. 13
      CoreAgent.Infrastructure/Extensions/ExceptionMiddlewareExtensions.cs
  24. 27
      CoreAgent.Infrastructure/Extensions/LoggingExtensions.cs
  25. 24
      CoreAgent.Infrastructure/Extensions/RequestLoggingExtensions.cs
  26. 65
      CoreAgent.Infrastructure/Logging/ApplicationLogger.cs
  27. 75
      CoreAgent.Infrastructure/Middleware/ExceptionMiddleware.cs
  28. 110
      CoreAgent.Infrastructure/Middleware/RequestLoggingMiddleware.cs
  29. 103
      CoreAgent.Infrastructure/Middleware/ResponseLoggingMiddleware.cs
  30. 45
      CoreAgent.Infrastructure/Options/ApiVersioningSettings.cs
  31. 35
      CoreAgent.Infrastructure/Options/RequestLoggingOptions.cs
  32. 40
      CoreAgent.sln

45
.gitignore

@ -0,0 +1,45 @@
# .NET Core
bin/
obj/
*.user
*.userosscache
*.suo
*.userprefs
.vs/
.vscode/
*.swp
*.*~
project.lock.json
.DS_Store
*.pyc
nupkg/
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
msbuild.log
msbuild.err
msbuild.wrn
# Visual Studio
.vs/
*.ncrunchsolution
*.ncrunchproject
*.DotSettings
*.DotSettings.user

12
CoreAgent.API/Configurations/api-versioning.json

@ -0,0 +1,12 @@
{
"ApiVersioning": {
"DefaultVersion": "1.0",
"ShowVersionInHeader": true,
"ShowVersionInResponse": true,
"ShowVersionInUrl": true,
"ShowVersionInQueryString": true,
"ShowVersionInMediaType": true,
"ReportApiVersions": true,
"AssumeDefaultVersionWhenUnspecified": true
}
}

30
CoreAgent.API/Configurations/logger.json

@ -0,0 +1,30 @@
{
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "logs/log-.txt",
"rollingInterval": "Day",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}",
"shared": true,
"flushToDiskInterval": "00:00:01"
}
}
],
"Enrich": [ "FromLogContext" ]
}
}

17
CoreAgent.API/Configurations/request-logging.Development.json

@ -0,0 +1,17 @@
{
"RequestLogging": {
"LogRequestBody": true,
"LogResponseBody": true,
"MaxRequestBodySize": 2097152,
"MaxResponseBodySize": 2097152,
"ExcludePaths": [
"/health",
"/metrics",
"/swagger",
"/favicon.ico"
],
"ExcludeMethods": [
"OPTIONS"
]
}
}

17
CoreAgent.API/Configurations/request-logging.json

@ -0,0 +1,17 @@
{
"RequestLogging": {
"LogRequestBody": true,
"LogResponseBody": true,
"MaxRequestBodySize": 1048576,
"MaxResponseBodySize": 1048576,
"ExcludePaths": [
"/health",
"/metrics",
"/swagger",
"/favicon.ico"
],
"ExcludeMethods": [
"OPTIONS"
]
}
}

45
CoreAgent.API/Controllers/WeatherForecastController.cs

@ -0,0 +1,45 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace CoreAgent.API.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly ILogger<WeatherForecastController> _logger;
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IActionResult Get()
{
_logger.LogInformation("Weather forecast requested");
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
Summaries[Random.Shared.Next(Summaries.Length)]
))
.ToArray();
_logger.LogDebug("Generated forecast for {Count} days", forecast.Length);
return Ok(forecast);
}
}
public record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
}

28
CoreAgent.API/CoreAgent.API.csproj

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="5.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.1.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CoreAgent.Infrastructure\CoreAgent.Infrastructure.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="Configurations\*.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

6
CoreAgent.API/CoreAgent.API.http

@ -0,0 +1,6 @@
@CoreAgent.API_HostAddress = http://localhost:5228
GET {{CoreAgent.API_HostAddress}}/weatherforecast/
Accept: application/json
###

67
CoreAgent.API/Program.cs

@ -0,0 +1,67 @@
using CoreAgent.API;
using CoreAgent.Infrastructure.Logging;
using Serilog;
using System;
using System.Text.Json;
var builder = WebApplication.CreateBuilder(args);
try
{
// 第一步:添加所有配置
builder.AddConfigurations();
// 第二步:创建Startup实例
var startup = builder.CreateStartup();
// 第三步:配置服务
startup.ConfigureServices(builder.Services);
var app = builder.Build();
// 配置中间件
startup.Configure(app);
// 配置Swagger
app.ConfigureSwagger();
Log.Information("Application startup completed");
// 注册应用程序关闭事件
var lifetime = app.Lifetime;
lifetime.ApplicationStopping.Register(() =>
{
Log.Information("Application is stopping...");
// 在这里可以添加清理代码,比如关闭数据库连接等
});
lifetime.ApplicationStopped.Register(() =>
{
Log.Information("Application has stopped.");
// 确保所有日志都被写入
Log.CloseAndFlush();
});
app.Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Application failed to start: {Message}", ex.Message);
// 记录详细的启动失败信息
var errorDetails = new
{
Message = ex.Message,
StackTrace = ex.StackTrace,
Source = ex.Source,
InnerException = ex.InnerException?.Message
};
Log.Fatal("Startup failure details: {Details}", JsonSerializer.Serialize(errorDetails));
// 确保所有日志都被写入
Log.CloseAndFlush();
// 使用非零退出码表示错误
Environment.Exit(1);
}

41
CoreAgent.API/Properties/launchSettings.json

@ -0,0 +1,41 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:3074",
"sslPort": 44378
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5228",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7133;http://localhost:5228",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

118
CoreAgent.API/Startup.cs

@ -0,0 +1,118 @@
using CoreAgent.Infrastructure.Extensions;
using CoreAgent.Infrastructure.Logging;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
namespace CoreAgent.API
{
public class Startup
{
public IConfiguration Configuration { get; }
public IHostEnvironment Environment { get; }
public Startup(IConfiguration configuration, IHostEnvironment environment)
{
Configuration = configuration;
Environment = environment;
}
public void ConfigureServices(IServiceCollection services)
{
// 添加基础设施服务
services.AddInfrastructure(Configuration);
// 添加控制器
services.AddControllers();
// 添加API文档
services.AddEndpointsApiExplorer();
services.AddSwaggerGen();
}
public void Configure(IApplicationBuilder app)
{
// 配置开发环境中间件
if (Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
Log.Debug("Swagger UI enabled in development environment");
}
// 使用基础设施中间件
app.UseInfrastructure(Configuration);
// 配置控制器路由
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
public static class StartupExtensions
{
public static WebApplicationBuilder AddConfigurations(this WebApplicationBuilder builder)
{
const string configurationsDirectory = "Configurations";
var env = builder.Environment;
// 基础配置
builder.Configuration
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
// 基础设施配置
builder.Configuration
.AddJsonFile($"{configurationsDirectory}/logger.json", optional: false, reloadOnChange: true)
.AddJsonFile($"{configurationsDirectory}/logger.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
.AddJsonFile($"{configurationsDirectory}/request-logging.json", optional: false, reloadOnChange: true)
.AddJsonFile($"{configurationsDirectory}/request-logging.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
.AddJsonFile($"{configurationsDirectory}/api-versioning.json", optional: false, reloadOnChange: true)
.AddJsonFile($"{configurationsDirectory}/api-versioning.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
return builder;
}
public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration config)
{
return services
.AddLoggingServices(config)
.AddApiVersioningExtension(config)
.AddRequestLogging(config)
.AddAuthorization()
.AddSwaggerGen();
}
public static IApplicationBuilder UseInfrastructure(this IApplicationBuilder app, IConfiguration config)
{
return app
.UseHttpsRedirection()
.UseExceptionMiddleware()
.UseAuthorization()
.UseRequestLogging(config)
.UseApiVersioningExtension();
}
public static void ConfigureSwagger(this WebApplication app)
{
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
}
// 新增:创建Startup实例的扩展方法
public static Startup CreateStartup(this WebApplicationBuilder builder)
{
return new Startup(builder.Configuration, builder.Environment);
}
}
}

8
CoreAgent.API/appsettings.Development.json

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

9
CoreAgent.API/appsettings.json

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

98
CoreAgent.API/logs/log-20250610.txt

@ -0,0 +1,98 @@
2025-06-10 23:09:05.046 +08:00 [INF] Logger initialized successfully
2025-06-10 23:09:05.092 +08:00 [INF] Application starting...
2025-06-10 23:09:06.063 +08:00 [FTL] Application failed to start: Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware Lifetime: Scoped ImplementationType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware': Unable to resolve service for type 'Microsoft.AspNetCore.Http.RequestDelegate' while attempting to activate 'CoreAgent.Infrastructure.Middleware.ExceptionMiddleware'.)
System.AggregateException: Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware Lifetime: Scoped ImplementationType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware': Unable to resolve service for type 'Microsoft.AspNetCore.Http.RequestDelegate' while attempting to activate 'CoreAgent.Infrastructure.Middleware.ExceptionMiddleware'.)
---> System.InvalidOperationException: Error while validating the service descriptor 'ServiceType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware Lifetime: Scoped ImplementationType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware': Unable to resolve service for type 'Microsoft.AspNetCore.Http.RequestDelegate' while attempting to activate 'CoreAgent.Infrastructure.Middleware.ExceptionMiddleware'.
---> System.InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Http.RequestDelegate' while attempting to activate 'CoreAgent.Infrastructure.Middleware.ExceptionMiddleware'.
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, Int32 slot)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(ServiceDescriptor serviceDescriptor, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.ValidateService(ServiceDescriptor descriptor)
--- End of inner exception stack trace ---
at Microsoft.Extensions.DependencyInjection.ServiceProvider.ValidateService(ServiceDescriptor descriptor)
at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection`1 serviceDescriptors, ServiceProviderOptions options)
--- End of inner exception stack trace ---
at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection`1 serviceDescriptors, ServiceProviderOptions options)
at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services, ServiceProviderOptions options)
at Microsoft.Extensions.Hosting.HostApplicationBuilder.Build()
at Microsoft.AspNetCore.Builder.WebApplicationBuilder.Build()
at Program.<Main>$(String[] args) in D:\HistoryCode\CoreAgent\src\CoreAgent.API\Program.cs:line 17
2025-06-10 23:09:06.162 +08:00 [FTL] Startup failure details: {"Message":"Some services are not able to be constructed (Error while validating the service descriptor \u0027ServiceType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware Lifetime: Scoped ImplementationType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware\u0027: Unable to resolve service for type \u0027Microsoft.AspNetCore.Http.RequestDelegate\u0027 while attempting to activate \u0027CoreAgent.Infrastructure.Middleware.ExceptionMiddleware\u0027.)","StackTrace":" at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection\u00601 serviceDescriptors, ServiceProviderOptions options)\r\n at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services, ServiceProviderOptions options)\r\n at Microsoft.Extensions.Hosting.HostApplicationBuilder.Build()\r\n at Microsoft.AspNetCore.Builder.WebApplicationBuilder.Build()\r\n at Program.\u003CMain\u003E$(String[] args) in D:\\HistoryCode\\CoreAgent\\src\\CoreAgent.API\\Program.cs:line 17","Source":"Microsoft.Extensions.DependencyInjection","InnerException":"Error while validating the service descriptor \u0027ServiceType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware Lifetime: Scoped ImplementationType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware\u0027: Unable to resolve service for type \u0027Microsoft.AspNetCore.Http.RequestDelegate\u0027 while attempting to activate \u0027CoreAgent.Infrastructure.Middleware.ExceptionMiddleware\u0027."}
2025-06-10 23:09:40.611 +08:00 [INF] Logger initialized successfully
2025-06-10 23:09:40.653 +08:00 [INF] Application starting...
2025-06-10 23:09:40.752 +08:00 [FTL] Application failed to start: Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware Lifetime: Scoped ImplementationType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware': Unable to resolve service for type 'Microsoft.AspNetCore.Http.RequestDelegate' while attempting to activate 'CoreAgent.Infrastructure.Middleware.ExceptionMiddleware'.)
System.AggregateException: Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware Lifetime: Scoped ImplementationType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware': Unable to resolve service for type 'Microsoft.AspNetCore.Http.RequestDelegate' while attempting to activate 'CoreAgent.Infrastructure.Middleware.ExceptionMiddleware'.)
---> System.InvalidOperationException: Error while validating the service descriptor 'ServiceType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware Lifetime: Scoped ImplementationType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware': Unable to resolve service for type 'Microsoft.AspNetCore.Http.RequestDelegate' while attempting to activate 'CoreAgent.Infrastructure.Middleware.ExceptionMiddleware'.
---> System.InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Http.RequestDelegate' while attempting to activate 'CoreAgent.Infrastructure.Middleware.ExceptionMiddleware'.
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, Int32 slot)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(ServiceDescriptor serviceDescriptor, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.ValidateService(ServiceDescriptor descriptor)
--- End of inner exception stack trace ---
at Microsoft.Extensions.DependencyInjection.ServiceProvider.ValidateService(ServiceDescriptor descriptor)
at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection`1 serviceDescriptors, ServiceProviderOptions options)
--- End of inner exception stack trace ---
at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection`1 serviceDescriptors, ServiceProviderOptions options)
at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services, ServiceProviderOptions options)
at Microsoft.Extensions.Hosting.HostApplicationBuilder.Build()
at Microsoft.AspNetCore.Builder.WebApplicationBuilder.Build()
at Program.<Main>$(String[] args) in D:\HistoryCode\CoreAgent\src\CoreAgent.API\Program.cs:line 17
2025-06-10 23:09:40.820 +08:00 [FTL] Startup failure details: {"Message":"Some services are not able to be constructed (Error while validating the service descriptor \u0027ServiceType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware Lifetime: Scoped ImplementationType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware\u0027: Unable to resolve service for type \u0027Microsoft.AspNetCore.Http.RequestDelegate\u0027 while attempting to activate \u0027CoreAgent.Infrastructure.Middleware.ExceptionMiddleware\u0027.)","StackTrace":" at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection\u00601 serviceDescriptors, ServiceProviderOptions options)\r\n at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services, ServiceProviderOptions options)\r\n at Microsoft.Extensions.Hosting.HostApplicationBuilder.Build()\r\n at Microsoft.AspNetCore.Builder.WebApplicationBuilder.Build()\r\n at Program.\u003CMain\u003E$(String[] args) in D:\\HistoryCode\\CoreAgent\\src\\CoreAgent.API\\Program.cs:line 17","Source":"Microsoft.Extensions.DependencyInjection","InnerException":"Error while validating the service descriptor \u0027ServiceType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware Lifetime: Scoped ImplementationType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware\u0027: Unable to resolve service for type \u0027Microsoft.AspNetCore.Http.RequestDelegate\u0027 while attempting to activate \u0027CoreAgent.Infrastructure.Middleware.ExceptionMiddleware\u0027."}
2025-06-10 23:10:25.939 +08:00 [INF] Logger initialized successfully
2025-06-10 23:10:25.975 +08:00 [INF] Application starting...
2025-06-10 23:10:26.021 +08:00 [FTL] Application failed to start: Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware Lifetime: Scoped ImplementationType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware': Unable to resolve service for type 'Microsoft.AspNetCore.Http.RequestDelegate' while attempting to activate 'CoreAgent.Infrastructure.Middleware.ExceptionMiddleware'.)
System.AggregateException: Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware Lifetime: Scoped ImplementationType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware': Unable to resolve service for type 'Microsoft.AspNetCore.Http.RequestDelegate' while attempting to activate 'CoreAgent.Infrastructure.Middleware.ExceptionMiddleware'.)
---> System.InvalidOperationException: Error while validating the service descriptor 'ServiceType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware Lifetime: Scoped ImplementationType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware': Unable to resolve service for type 'Microsoft.AspNetCore.Http.RequestDelegate' while attempting to activate 'CoreAgent.Infrastructure.Middleware.ExceptionMiddleware'.
---> System.InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Http.RequestDelegate' while attempting to activate 'CoreAgent.Infrastructure.Middleware.ExceptionMiddleware'.
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, Int32 slot)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(ServiceDescriptor serviceDescriptor, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.ValidateService(ServiceDescriptor descriptor)
--- End of inner exception stack trace ---
at Microsoft.Extensions.DependencyInjection.ServiceProvider.ValidateService(ServiceDescriptor descriptor)
at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection`1 serviceDescriptors, ServiceProviderOptions options)
--- End of inner exception stack trace ---
at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection`1 serviceDescriptors, ServiceProviderOptions options)
at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services, ServiceProviderOptions options)
at Microsoft.Extensions.Hosting.HostApplicationBuilder.Build()
at Microsoft.AspNetCore.Builder.WebApplicationBuilder.Build()
at Program.<Main>$(String[] args) in D:\HistoryCode\CoreAgent\src\CoreAgent.API\Program.cs:line 17
2025-06-10 23:10:26.056 +08:00 [FTL] Startup failure details: {"Message":"Some services are not able to be constructed (Error while validating the service descriptor \u0027ServiceType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware Lifetime: Scoped ImplementationType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware\u0027: Unable to resolve service for type \u0027Microsoft.AspNetCore.Http.RequestDelegate\u0027 while attempting to activate \u0027CoreAgent.Infrastructure.Middleware.ExceptionMiddleware\u0027.)","StackTrace":" at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection\u00601 serviceDescriptors, ServiceProviderOptions options)\r\n at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services, ServiceProviderOptions options)\r\n at Microsoft.Extensions.Hosting.HostApplicationBuilder.Build()\r\n at Microsoft.AspNetCore.Builder.WebApplicationBuilder.Build()\r\n at Program.\u003CMain\u003E$(String[] args) in D:\\HistoryCode\\CoreAgent\\src\\CoreAgent.API\\Program.cs:line 17","Source":"Microsoft.Extensions.DependencyInjection","InnerException":"Error while validating the service descriptor \u0027ServiceType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware Lifetime: Scoped ImplementationType: CoreAgent.Infrastructure.Middleware.ExceptionMiddleware\u0027: Unable to resolve service for type \u0027Microsoft.AspNetCore.Http.RequestDelegate\u0027 while attempting to activate \u0027CoreAgent.Infrastructure.Middleware.ExceptionMiddleware\u0027."}
2025-06-10 23:11:14.432 +08:00 [INF] Logger initialized successfully
2025-06-10 23:11:14.474 +08:00 [INF] Application starting...
2025-06-10 23:11:14.527 +08:00 [FTL] Application failed to start: Unable to find the required services. Please add all the required services by calling 'IServiceCollection.AddAuthorization' in the application startup code.
System.InvalidOperationException: Unable to find the required services. Please add all the required services by calling 'IServiceCollection.AddAuthorization' in the application startup code.
at Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions.VerifyServicesRegistered(IApplicationBuilder app)
at Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions.UseAuthorization(IApplicationBuilder app)
at CoreAgent.API.Startup.UseInfrastructure(IApplicationBuilder app, IConfiguration config) in D:\HistoryCode\CoreAgent\src\CoreAgent.API\Startup.cs:line 45
at Program.<Main>$(String[] args) in D:\HistoryCode\CoreAgent\src\CoreAgent.API\Program.cs:line 28
2025-06-10 23:11:14.601 +08:00 [FTL] Startup failure details: {"Message":"Unable to find the required services. Please add all the required services by calling \u0027IServiceCollection.AddAuthorization\u0027 in the application startup code.","StackTrace":" at Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions.VerifyServicesRegistered(IApplicationBuilder app)\r\n at Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions.UseAuthorization(IApplicationBuilder app)\r\n at CoreAgent.API.Startup.UseInfrastructure(IApplicationBuilder app, IConfiguration config) in D:\\HistoryCode\\CoreAgent\\src\\CoreAgent.API\\Startup.cs:line 45\r\n at Program.\u003CMain\u003E$(String[] args) in D:\\HistoryCode\\CoreAgent\\src\\CoreAgent.API\\Program.cs:line 28","Source":"Microsoft.AspNetCore.Authorization.Policy","InnerException":null}
2025-06-10 23:14:51.039 +08:00 [INF] Logger initialized successfully
2025-06-10 23:14:51.069 +08:00 [INF] Application starting...
2025-06-10 23:14:51.124 +08:00 [FTL] Application failed to start: Unable to find the required services. Please add all the required services by calling 'IServiceCollection.AddAuthorization' in the application startup code.
System.InvalidOperationException: Unable to find the required services. Please add all the required services by calling 'IServiceCollection.AddAuthorization' in the application startup code.
at Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions.VerifyServicesRegistered(IApplicationBuilder app)
at Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions.UseAuthorization(IApplicationBuilder app)
at CoreAgent.API.Startup.UseInfrastructure(IApplicationBuilder app, IConfiguration config) in D:\HistoryCode\CoreAgent\src\CoreAgent.API\Startup.cs:line 45
at Program.<Main>$(String[] args) in D:\HistoryCode\CoreAgent\src\CoreAgent.API\Program.cs:line 28
2025-06-10 23:14:51.149 +08:00 [FTL] Startup failure details: {"Message":"Unable to find the required services. Please add all the required services by calling \u0027IServiceCollection.AddAuthorization\u0027 in the application startup code.","StackTrace":" at Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions.VerifyServicesRegistered(IApplicationBuilder app)\r\n at Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions.UseAuthorization(IApplicationBuilder app)\r\n at CoreAgent.API.Startup.UseInfrastructure(IApplicationBuilder app, IConfiguration config) in D:\\HistoryCode\\CoreAgent\\src\\CoreAgent.API\\Startup.cs:line 45\r\n at Program.\u003CMain\u003E$(String[] args) in D:\\HistoryCode\\CoreAgent\\src\\CoreAgent.API\\Program.cs:line 28","Source":"Microsoft.AspNetCore.Authorization.Policy","InnerException":null}
2025-06-10 23:15:27.651 +08:00 [INF] Logger initialized successfully
2025-06-10 23:15:27.682 +08:00 [INF] Application starting...
2025-06-10 23:15:27.735 +08:00 [INF] Application startup completed
2025-06-10 23:23:44.793 +08:00 [INF] Logger initialized successfully
2025-06-10 23:23:44.837 +08:00 [INF] Application starting...
2025-06-10 23:23:45.207 +08:00 [INF] Application startup completed
2025-06-10 23:23:51.434 +08:00 [INF] Request started: GET /api/v1/WeatherForecast
2025-06-10 23:23:51.497 +08:00 [INF] Weather forecast requested
2025-06-10 23:23:51.530 +08:00 [INF] Response for GET /api/v1/WeatherForecast: 200 - [{"date":"2025-06-11","temperatureC":-19,"summary":"Scorching","temperatureF":-2},{"date":"2025-06-12","temperatureC":-11,"summary":"Bracing","temperatureF":13},{"date":"2025-06-13","temperatureC":10,"summary":"Chilly","temperatureF":49},{"date":"2025-06-14","temperatureC":7,"summary":"Mild","temperatureF":44},{"date":"2025-06-15","temperatureC":35,"summary":"Warm","temperatureF":94}]
2025-06-10 23:23:51.547 +08:00 [INF] Request completed: GET /api/v1/WeatherForecast in 119ms with status code 200
2025-06-10 23:24:10.107 +08:00 [INF] Logger initialized successfully
2025-06-10 23:24:10.148 +08:00 [INF] Application starting...
2025-06-10 23:24:10.527 +08:00 [INF] Application startup completed
2025-06-10 23:24:23.522 +08:00 [INF] Request started: GET /api/v1/WeatherForecast
2025-06-10 23:24:23.584 +08:00 [INF] Weather forecast requested
2025-06-10 23:24:23.612 +08:00 [INF] Response for GET /api/v1/WeatherForecast: 200 - [{"date":"2025-06-11","temperatureC":24,"summary":"Warm","temperatureF":75},{"date":"2025-06-12","temperatureC":4,"summary":"Bracing","temperatureF":39},{"date":"2025-06-13","temperatureC":54,"summary":"Chilly","temperatureF":129},{"date":"2025-06-14","temperatureC":-6,"summary":"Freezing","temperatureF":22},{"date":"2025-06-15","temperatureC":-20,"summary":"Sweltering","temperatureF":-3}]
2025-06-10 23:24:23.632 +08:00 [INF] Request completed: GET /api/v1/WeatherForecast in 120ms with status code 200

9
CoreAgent.Application/CoreAgent.Application.csproj

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

13
CoreAgent.Domain/CoreAgent.Domain.csproj

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
</ItemGroup>
</Project>

14
CoreAgent.Domain/Exceptions/NotFoundException.cs

@ -0,0 +1,14 @@
namespace CoreAgent.Domain.Exceptions
{
public class NotFoundException : Exception
{
public NotFoundException(string message) : base(message)
{
}
public NotFoundException(string name, object key)
: base($"Entity \"{name}\" ({key}) was not found.")
{
}
}
}

17
CoreAgent.Domain/Exceptions/ValidationException.cs

@ -0,0 +1,17 @@
namespace CoreAgent.Domain.Exceptions
{
public class ValidationException : Exception
{
public IDictionary<string, string[]> Errors { get; }
public ValidationException(string message) : base(message)
{
Errors = new Dictionary<string, string[]>();
}
public ValidationException(string message, IDictionary<string, string[]> errors) : base(message)
{
Errors = errors;
}
}
}

23
CoreAgent.Domain/Models/ErrorResponse.cs

@ -0,0 +1,23 @@
namespace CoreAgent.Domain.Models
{
/// <summary>
/// 表示API错误响应的领域模型
/// </summary>
public class ErrorResponse
{
/// <summary>
/// 请求的唯一跟踪标识符
/// </summary>
public string TraceId { get; set; }
/// <summary>
/// 错误消息
/// </summary>
public string Message { get; set; }
/// <summary>
/// 验证错误集合,键为字段名,值为错误消息数组
/// </summary>
public IDictionary<string, string[]> Errors { get; set; }
}
}

28
CoreAgent.Infrastructure/CoreAgent.Infrastructure.csproj

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="5.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" />
<PackageReference Include="Serilog" Version="3.1.1" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CoreAgent.Domain\CoreAgent.Domain.csproj" />
</ItemGroup>
</Project>

13
CoreAgent.Infrastructure/CoreAgent.Infrastructure.csproj.Backup.tmp

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Serilog" Version="4.3.0" />
</ItemGroup>
</Project>

44
CoreAgent.Infrastructure/Extensions/ApiVersioningExtensions.cs

@ -0,0 +1,44 @@
using CoreAgent.Infrastructure.Options;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace CoreAgent.Infrastructure.Extensions
{
public static class ApiVersioningExtensions
{
public static IServiceCollection AddApiVersioningExtension(this IServiceCollection services, IConfiguration config)
{
var settings = config.GetSection("ApiVersioning").Get<ApiVersioningSettings>() ?? new ApiVersioningSettings();
services.AddApiVersioning(options =>
{
options.DefaultApiVersion = ApiVersion.Parse(settings.DefaultVersion);
options.AssumeDefaultVersionWhenUnspecified = settings.AssumeDefaultVersionWhenUnspecified;
options.ReportApiVersions = settings.ReportApiVersions;
options.ApiVersionReader = ApiVersionReader.Combine(
settings.ShowVersionInUrl ? new UrlSegmentApiVersionReader() : null,
settings.ShowVersionInQueryString ? new QueryStringApiVersionReader("api-version") : null,
settings.ShowVersionInHeader ? new HeaderApiVersionReader("api-version") : null,
settings.ShowVersionInMediaType ? new MediaTypeApiVersionReader("version") : null
);
});
services.AddVersionedApiExplorer(options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});
return services;
}
public static IApplicationBuilder UseApiVersioningExtension(this IApplicationBuilder app)
{
// 可以在这里添加版本控制相关的中间件
return app;
}
}
}

13
CoreAgent.Infrastructure/Extensions/ExceptionMiddlewareExtensions.cs

@ -0,0 +1,13 @@
using CoreAgent.Infrastructure.Middleware;
using Microsoft.AspNetCore.Builder;
namespace CoreAgent.Infrastructure.Extensions
{
public static class ExceptionMiddlewareExtensions
{
public static IApplicationBuilder UseExceptionMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<ExceptionMiddleware>();
}
}
}

27
CoreAgent.Infrastructure/Extensions/LoggingExtensions.cs

@ -0,0 +1,27 @@
using CoreAgent.Infrastructure.Logging;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Serilog;
namespace CoreAgent.Infrastructure.Extensions
{
public static class LoggingExtensions
{
public static IServiceCollection AddLoggingServices(this IServiceCollection services, IConfiguration configuration)
{
// 初始化应用程序日志记录器
ApplicationLogger.Initialize(configuration);
Log.Information("Application starting...");
// 添加 Serilog 到依赖注入容器
services.AddLogging(loggingBuilder =>
{
loggingBuilder.ClearProviders();
loggingBuilder.AddSerilog(dispose: true);
});
return services;
}
}
}

24
CoreAgent.Infrastructure/Extensions/RequestLoggingExtensions.cs

@ -0,0 +1,24 @@
using CoreAgent.Infrastructure.Middleware;
using CoreAgent.Infrastructure.Options;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace CoreAgent.Infrastructure.Extensions
{
public static class RequestLoggingExtensions
{
public static IServiceCollection AddRequestLogging(this IServiceCollection services, IConfiguration config)
{
services.Configure<RequestLoggingOptions>(config.GetSection("RequestLogging"));
return services;
}
public static IApplicationBuilder UseRequestLogging(this IApplicationBuilder app, IConfiguration config)
{
app.UseMiddleware<RequestLoggingMiddleware>();
app.UseMiddleware<ResponseLoggingMiddleware>();
return app;
}
}
}

65
CoreAgent.Infrastructure/Logging/ApplicationLogger.cs

@ -0,0 +1,65 @@
using Microsoft.Extensions.Configuration;
using Serilog;
using System;
using System.IO;
namespace CoreAgent.Infrastructure.Logging
{
public static class ApplicationLogger
{
private static readonly object _lock = new object();
private static bool _isInitialized;
public static void Initialize(IConfiguration configuration)
{
ArgumentNullException.ThrowIfNull(configuration, nameof(configuration));
if (_isInitialized)
{
return;
}
lock (_lock)
{
if (_isInitialized)
{
return;
}
try
{
// 确保日志目录存在
var logDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
Directory.CreateDirectory(logDirectory);
// 从配置文件初始化
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
_isInitialized = true;
Log.Information("Logger initialized successfully");
}
catch (Exception ex)
{
// 如果初始化失败,创建一个基本的控制台日志记录器
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console()
.CreateLogger();
_isInitialized = true;
Log.Error(ex, "Failed to initialize logger with full configuration");
}
}
}
public static void EnsureInitialized()
{
if (!_isInitialized)
{
throw new InvalidOperationException("Logger has not been initialized. Call Initialize() first.");
}
}
}
}

75
CoreAgent.Infrastructure/Middleware/ExceptionMiddleware.cs

@ -0,0 +1,75 @@
using CoreAgent.Domain.Exceptions;
using CoreAgent.Domain.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Net;
using System.Text.Json;
namespace CoreAgent.Infrastructure.Middleware
{
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<ExceptionMiddleware> _logger;
public ExceptionMiddleware(RequestDelegate next, ILogger<ExceptionMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
var response = context.Response;
response.ContentType = "application/json";
var errorResponse = new ErrorResponse
{
TraceId = context.TraceIdentifier,
Message = "An error occurred while processing your request."
};
switch (exception)
{
case ValidationException validationEx:
response.StatusCode = (int)HttpStatusCode.BadRequest;
errorResponse.Message = validationEx.Message;
errorResponse.Errors = validationEx.Errors;
_logger.LogWarning("Validation error: {Message}", validationEx.Message);
break;
case NotFoundException notFoundEx:
response.StatusCode = (int)HttpStatusCode.NotFound;
errorResponse.Message = notFoundEx.Message;
_logger.LogWarning("Resource not found: {Message}", notFoundEx.Message);
break;
case UnauthorizedAccessException:
response.StatusCode = (int)HttpStatusCode.Unauthorized;
errorResponse.Message = "You are not authorized to access this resource.";
_logger.LogWarning("Unauthorized access attempt");
break;
default:
response.StatusCode = (int)HttpStatusCode.InternalServerError;
_logger.LogError(exception, "Unhandled exception occurred");
break;
}
var result = JsonSerializer.Serialize(errorResponse);
await response.WriteAsync(result);
}
}
}

110
CoreAgent.Infrastructure/Middleware/RequestLoggingMiddleware.cs

@ -0,0 +1,110 @@
using CoreAgent.Infrastructure.Options;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Diagnostics;
using System.Text;
namespace CoreAgent.Infrastructure.Middleware
{
public class RequestLoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestLoggingMiddleware> _logger;
private readonly RequestLoggingOptions _options;
public RequestLoggingMiddleware(
RequestDelegate next,
ILogger<RequestLoggingMiddleware> logger,
IOptions<RequestLoggingOptions> options)
{
_next = next;
_logger = logger;
_options = options.Value;
}
public async Task InvokeAsync(HttpContext context)
{
if (ShouldSkipLogging(context))
{
await _next(context);
return;
}
var sw = Stopwatch.StartNew();
var requestBody = string.Empty;
try
{
if (_options.LogRequestBody && context.Request.Body != null)
{
requestBody = await ReadRequestBodyAsync(context.Request);
}
_logger.LogInformation(
"Request started: {Method} {Path} {QueryString} {RequestBody}",
context.Request.Method,
context.Request.Path,
context.Request.QueryString,
requestBody);
await _next(context);
}
finally
{
sw.Stop();
_logger.LogInformation(
"Request completed: {Method} {Path} in {ElapsedMilliseconds}ms with status code {StatusCode}",
context.Request.Method,
context.Request.Path,
sw.ElapsedMilliseconds,
context.Response.StatusCode);
}
}
private bool ShouldSkipLogging(HttpContext context)
{
if (_options.ExcludePaths.Any(p => context.Request.Path.StartsWithSegments(p)))
{
return true;
}
if (_options.ExcludeMethods.Contains(context.Request.Method))
{
return true;
}
return false;
}
private async Task<string> ReadRequestBodyAsync(HttpRequest request)
{
if (!request.Body.CanRead || !request.Body.CanSeek)
{
return string.Empty;
}
var originalPosition = request.Body.Position;
request.Body.Position = 0;
try
{
using var reader = new StreamReader(
request.Body,
encoding: Encoding.UTF8,
detectEncodingFromByteOrderMarks: false,
bufferSize: 1024 * 45,
leaveOpen: true);
var body = await reader.ReadToEndAsync();
return body.Length > _options.MaxRequestBodySize
? body.Substring(0, _options.MaxRequestBodySize) + "..."
: body;
}
finally
{
request.Body.Position = originalPosition;
}
}
}
}

103
CoreAgent.Infrastructure/Middleware/ResponseLoggingMiddleware.cs

@ -0,0 +1,103 @@
using CoreAgent.Infrastructure.Options;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Text;
namespace CoreAgent.Infrastructure.Middleware
{
public class ResponseLoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<ResponseLoggingMiddleware> _logger;
private readonly RequestLoggingOptions _options;
public ResponseLoggingMiddleware(
RequestDelegate next,
ILogger<ResponseLoggingMiddleware> logger,
IOptions<RequestLoggingOptions> options)
{
_next = next;
_logger = logger;
_options = options.Value;
}
public async Task InvokeAsync(HttpContext context)
{
if (ShouldSkipLogging(context))
{
await _next(context);
return;
}
// 保存原始响应流
var originalBodyStream = context.Response.Body;
try
{
// 创建一个新的内存流来捕获响应
using var responseBody = new MemoryStream();
context.Response.Body = responseBody;
// 继续处理请求
await _next(context);
// 读取响应内容
responseBody.Seek(0, SeekOrigin.Begin);
var response = await ReadResponseBodyAsync(responseBody);
// 记录响应
_logger.LogInformation(
"Response for {Method} {Path}: {StatusCode} - {Response}",
context.Request.Method,
context.Request.Path,
context.Response.StatusCode,
response);
// 将响应写回原始流
responseBody.Seek(0, SeekOrigin.Begin);
await responseBody.CopyToAsync(originalBodyStream);
}
finally
{
// 确保响应体被恢复
context.Response.Body = originalBodyStream;
}
}
private bool ShouldSkipLogging(HttpContext context)
{
if (!_options.LogResponseBody)
{
return true;
}
if (_options.ExcludePaths.Any(p => context.Request.Path.StartsWithSegments(p)))
{
return true;
}
if (_options.ExcludeMethods.Contains(context.Request.Method))
{
return true;
}
return false;
}
private async Task<string> ReadResponseBodyAsync(Stream responseBody)
{
using var reader = new StreamReader(
responseBody,
encoding: Encoding.UTF8,
detectEncodingFromByteOrderMarks: false,
bufferSize: 1024 * 45,
leaveOpen: true);
var body = await reader.ReadToEndAsync();
return body.Length > _options.MaxResponseBodySize
? body.Substring(0, _options.MaxResponseBodySize) + "..."
: body;
}
}
}

45
CoreAgent.Infrastructure/Options/ApiVersioningSettings.cs

@ -0,0 +1,45 @@
namespace CoreAgent.Infrastructure.Options
{
public class ApiVersioningSettings
{
/// <summary>
/// 默认 API 版本
/// </summary>
public string DefaultVersion { get; set; } = "1.0";
/// <summary>
/// 是否在响应头中显示版本信息
/// </summary>
public bool ShowVersionInHeader { get; set; } = true;
/// <summary>
/// 是否在响应中显示版本信息
/// </summary>
public bool ShowVersionInResponse { get; set; } = true;
/// <summary>
/// 是否在 URL 中显示版本信息
/// </summary>
public bool ShowVersionInUrl { get; set; } = true;
/// <summary>
/// 是否在查询字符串中显示版本信息
/// </summary>
public bool ShowVersionInQueryString { get; set; } = true;
/// <summary>
/// 是否在媒体类型中显示版本信息
/// </summary>
public bool ShowVersionInMediaType { get; set; } = true;
/// <summary>
/// 是否报告 API 版本
/// </summary>
public bool ReportApiVersions { get; set; } = true;
/// <summary>
/// 是否假设默认版本
/// </summary>
public bool AssumeDefaultVersionWhenUnspecified { get; set; } = true;
}
}

35
CoreAgent.Infrastructure/Options/RequestLoggingOptions.cs

@ -0,0 +1,35 @@
namespace CoreAgent.Infrastructure.Options
{
public class RequestLoggingOptions
{
/// <summary>
/// 是否记录请求体
/// </summary>
public bool LogRequestBody { get; set; } = true;
/// <summary>
/// 是否记录响应体
/// </summary>
public bool LogResponseBody { get; set; } = true;
/// <summary>
/// 最大请求体大小(字节)
/// </summary>
public int MaxRequestBodySize { get; set; } = 1024 * 1024; // 1MB
/// <summary>
/// 最大响应体大小(字节)
/// </summary>
public int MaxResponseBodySize { get; set; } = 1024 * 1024; // 1MB
/// <summary>
/// 要排除的路径列表
/// </summary>
public string[] ExcludePaths { get; set; } = Array.Empty<string>();
/// <summary>
/// 要排除的HTTP方法列表
/// </summary>
public string[] ExcludeMethods { get; set; } = Array.Empty<string>();
}
}

40
CoreAgent.sln

@ -0,0 +1,40 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoreAgent.API", "CoreAgent.API\CoreAgent.API.csproj", "{DC3259F5-9A7E-1AEA-FA79-13C78AA9FDAC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoreAgent.Application", "CoreAgent.Application\CoreAgent.Application.csproj", "{D74FF074-0A13-BF0E-A637-41E48C0FB9AB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoreAgent.Domain", "CoreAgent.Domain\CoreAgent.Domain.csproj", "{3269E8BF-134E-9410-E1DA-A62044875E72}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoreAgent.Infrastructure", "CoreAgent.Infrastructure\CoreAgent.Infrastructure.csproj", "{3EBCA8A2-F1CD-23F7-C943-0CAADACFFCDD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DC3259F5-9A7E-1AEA-FA79-13C78AA9FDAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DC3259F5-9A7E-1AEA-FA79-13C78AA9FDAC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DC3259F5-9A7E-1AEA-FA79-13C78AA9FDAC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DC3259F5-9A7E-1AEA-FA79-13C78AA9FDAC}.Release|Any CPU.Build.0 = Release|Any CPU
{D74FF074-0A13-BF0E-A637-41E48C0FB9AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D74FF074-0A13-BF0E-A637-41E48C0FB9AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D74FF074-0A13-BF0E-A637-41E48C0FB9AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D74FF074-0A13-BF0E-A637-41E48C0FB9AB}.Release|Any CPU.Build.0 = Release|Any CPU
{3269E8BF-134E-9410-E1DA-A62044875E72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3269E8BF-134E-9410-E1DA-A62044875E72}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3269E8BF-134E-9410-E1DA-A62044875E72}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3269E8BF-134E-9410-E1DA-A62044875E72}.Release|Any CPU.Build.0 = Release|Any CPU
{3EBCA8A2-F1CD-23F7-C943-0CAADACFFCDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3EBCA8A2-F1CD-23F7-C943-0CAADACFFCDD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3EBCA8A2-F1CD-23F7-C943-0CAADACFFCDD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3EBCA8A2-F1CD-23F7-C943-0CAADACFFCDD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
Loading…
Cancel
Save