using System.Text.Json.Serialization;
using System.Threading.RateLimiting;
using AgileConfig.Client;
using Dpz.Core.Hangfire;
using Dpz.Core.Infrastructure.Configuration;
using Dpz.Core.WebApi.Security;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.RateLimiting;
using Microsoft.OpenApi;
using Scalar.AspNetCore;
const string originsName = "Open";
Log.Logger = new LoggerConfiguration().Enrich.FromLogContext().CreateBootstrapLogger();
try
{
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseAgileConfig(new ConfigClient(builder.Configuration));
var configuration = builder.Configuration;
var seq = configuration.GetSection("LogSeq").Get<LogSeq>();
builder.Host.ConfigurationLog(seq);
#region services
var services = builder.Services;
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
options.KnownIPNetworks.Clear();
options.KnownProxies.Clear();
});
services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter(
"comment",
opt =>
{
opt.AutoReplenishment = true;
opt.PermitLimit = 3;
opt.Window = TimeSpan.FromMinutes(1);
opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
opt.QueueLimit = 2;
}
);
});
// IoC
services.AddDefaultServices(configuration).AddAppScoped();
services
.AddControllers()
// .AddXmlDataContractSerializerFormatters()
//.AddXmlSerializerFormatters()
.AddMessagePackSerializerFormatters()
.AddJsonOptions(opts =>
{
opts.JsonSerializerOptions.Converters.Add(new TimeSpanConverter());
opts.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
services.AddResponseCompression(options =>
{
options.Providers.Add<BrotliCompressionProvider>();
options.Providers.Add<GzipCompressionProvider>();
options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat([
"application/font-woff2",
"image/svg+xml",
"text/plain",
"application/lrc",
]);
});
services.Configure<BrotliCompressionProviderOptions>(options =>
{
options.Level = CompressionLevel.Optimal;
});
services.Configure<GzipCompressionProviderOptions>(options =>
{
options.Level = CompressionLevel.Optimal;
});
services.Configure<KestrelServerOptions>(options =>
{
options.Limits.MaxRequestBodySize = int.MaxValue;
});
services.AddEndpointsApiExplorer();
services.AddOutputCache(options =>
{
options.AddBasePolicy(policy => policy.Expire(TimeSpan.FromMinutes(10)));
});
services.AddOpenApi(options =>
{
options.AddDocumentTransformer(
async (doc, _, cancelToken) =>
{
var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
var description = "";
if (!string.IsNullOrEmpty(basePath))
{
var readmePath = Path.Combine(basePath, "README.md");
if (File.Exists(readmePath))
{
description = await File.ReadAllTextAsync(readmePath, cancelToken);
}
}
doc.Info.Description = description;
doc.Components ??= new OpenApiComponents();
doc.Components.SecuritySchemes ??= new Dictionary<string, IOpenApiSecurityScheme>();
doc.Components.SecuritySchemes.TryAdd(
"Bearer",
new OpenApiSecurityScheme
{
Description = "使用Bearer方案的JWT授权标头(示例:“ Bearer JWT_Token”)",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.OAuth2,
Scheme = "Bearer",
BearerFormat = "JWT",
}
);
doc.Security ??= new List<OpenApiSecurityRequirement>();
doc.Security.Add(
new OpenApiSecurityRequirement
{
{
new OpenApiSecuritySchemeReference("Bearer")
{
Reference = new OpenApiReferenceWithDescription
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer",
},
},
[]
},
}
);
}
);
});
services.AddBusinessServices(configuration);
// Cors
services.AddCors(options =>
{
options.AddPolicy(
originsName,
cfg =>
{
var origins = configuration.GetSection("Origins").Get<string[]>() ?? [];
cfg.WithOrigins(origins)
.WithMethods("GET", "PUT", "POST", "DELETE", "PATCH")
.AllowAnyHeader();
}
);
});
var issuer = configuration["Server:Issuer"] ?? throw new InvalidConfigurationException();
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = issuer;
options.Audience = "resource_server";
options.RequireHttpsMetadata = true;
options.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
Log.Error(context.Exception, "Failed to authenticate");
return Task.CompletedTask;
},
};
});
services.AddPermissionAuthorization();
services.AddRazorPages();
var webApiHangfireCollectionPrefix =
configuration["WebApiHangfireCollectionPrefix"]
?? throw new InvalidConfigurationException();
services.AddHangfireService(configuration, webApiHangfireCollectionPrefix);
#endregion
var app = builder.Build();
#region configuration
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseForwardedHeaders();
app.UseSerilogRequestLogging(options =>
{
options.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
{
diagnosticContext.Set("RequestHost", httpContext.Request.Host.Value);
diagnosticContext.Set("RequestScheme", httpContext.Request.Scheme);
diagnosticContext.Set(
"UserAgent",
httpContext.Request.Headers["User-Agent"].ToString()
);
diagnosticContext.Set("IpAddress", httpContext.Request.GetIpAddress());
};
});
app.UseResponseHeaders().UseRequestRecord().UseDateTimeLocalFormat();
app.UseResponseCompression();
app.MapOpenApi().CacheOutput();
app.MapScalarApiReference(options =>
{
options.Title = "Dpz.Core.WebApi";
options.Favicon = "https://dpangzi.com/favicon.ico";
options.Theme = ScalarTheme.Moon;
options.HideDarkModeToggle = false;
});
app.GetHostingEnvironment();
// //强制HTTPS
// app.UseHttpsRedirection();
app.UseRouting();
app.MapRazorPages();
app.UseCors(originsName);
//身份认证
app.UseAuthentication();
//身份授权
app.UseAuthorization();
app.MapControllers();
//app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
#if DEBUG
app.HangfireSetting();
#endif
#endregion
app.MapGet("/ping", () => "pong");
app.MapGet(
"/datetime",
() => $"{DateTime.Now:yyyy/Mm/dd HH:mm:ss}\r\n{Environment.MachineName}"
);
Log.Information("Starting web api host,current process id:{ID}", Environment.ProcessId);
app.Run();
}
catch (Exception e)
{
Console.Error.WriteLine(e);
Log.Fatal(e, "Host terminated unexpectedly");
}
/// <summary>
///
/// </summary>
public partial class Program
{
/// <summary>
/// 身份认证Cookie名称
/// </summary>
public const string AuthorizeCookieName = "Dpz.Web.Api.Server.Authoriza";
/// <summary>
/// 账号Cookie名称
/// </summary>
public const string AccountCookieName = "Dpz.Web.Api.Server.Account";
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
这段代码是一个 ASP.NET Core Web API 应用程序的启动代码,主要功能包括配置服务、设置中间件、处理请求和响应等。以下是对代码的详细解释:
1. 引入命名空间
代码开始部分引入了一些必要的命名空间,包括日志、配置、依赖注入、数据保护、Hangfire、Swagger等。
2. 日志配置
使用 Serilog 进行日志记录,创建一个引导日志记录器。
3. 创建 Web 应用程序
使用 WebApplication.CreateBuilder(args) 创建一个 Web 应用程序的构建器。
4. 配置 AgileConfig
通过 builder.Host.UseAgileConfig 使用 AgileConfig 进行配置管理。
5. 配置线程池
设置最小工作线程数,确保应用程序能够处理并发请求。
6. 服务配置
在 #region services 部分,配置了多个服务:
- IoC 容器:使用
AddDefaultServices和AddAppScoped方法注册默认服务和应用程序范围的服务。 - 控制器:添加控制器支持,并配置 JSON、XML 和 MessagePack 序列化选项。
- 响应压缩:配置 Brotli 和 Gzip 压缩。
- Kestrel 服务器选项:设置最大请求体大小。
- Swagger:配置 Swagger 文档生成,包括 API 文档和安全定义。
- Redis 缓存:添加 Redis 缓存服务。
- CORS:配置跨源资源共享策略。
- 身份验证:使用 JWT Bearer 进行身份验证,配置 Token 管理。
- 数据保护:配置数据保护服务。
- 授权:添加授权策略。
- Razor Pages:配置 Razor 页面路由。
- Hangfire:配置 Hangfire 服务用于后台任务处理。
7. 中间件配置
在 #region configuration 部分,配置了中间件:
- 开发环境异常页面:在开发环境中使用开发者异常页面。
- 请求日志记录:使用 Serilog 记录请求日志。
- 响应头、请求记录和日期时间格式:配置响应头、请求记录和日期时间格式。
- 响应压缩:启用响应压缩。
- Swagger UI:配置 Swagger UI 的路由。
- API 路由:配置 API 路由和主题。
- 强制 HTTPS:可以选择强制使用 HTTPS(注释掉了)。
- 路由:启用路由功能。
- CORS:使用配置的 CORS 策略。
- 身份验证和授权:启用身份验证和授权中间件。
- 控制器映射:映射控制器路由。
8. 其他功能
- 提供了两个简单的 GET 路由
/ping和/datetime,用于测试 API 是否正常工作。 - 记录应用程序启动信息。
9. 异常处理
在 catch 块中捕获异常并记录错误信息。
10. 类定义
定义了一个 Program 类,包含一些常量用于身份认证和账号 Cookie 的名称。
总结
这段代码是一个完整的 ASP.NET Core Web API 应用程序的启动配置,涵盖了服务注册、中间件配置、日志记录、身份验证、授权、CORS、Swagger 文档生成等多个方面,旨在提供一个功能齐全的 Web API 服务。
评论加载中...