Program.cs
7.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
using FreeSql.Internal;
using HaHRCS.Rcs.Dal.Repository;
using HaHRCS.Rcs.Executor.PLC;
using HHECS.Communication;
using MassTransit.JobService;
using Microsoft.Extensions.DependencyInjection;
using Rcs.Api;
using Rcs.Api.BackgroundServices;
using Rcs.Api.Hubs;
using Rcs.Infrastructure.DB.Repositories;
using Rcs.Infrastructure.Installs;
using Rcs.Infrastructure.PathFinding;
using Serilog;
// 配置 Serilog 日志
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
.Build())
.CreateLogger();
try
{
var builder = WebApplication.CreateBuilder(args);
string externalBaseUrl = builder.Configuration["AppSettings:ExternalBaseUrl"];
// 结果:"http://localhost:5000"
// 2. 读取嵌套的数据库连接字符串
string sqlConnStr = builder.Configuration["AppSettings:ConnSql:ConnectionString"];
if (string.IsNullOrEmpty(sqlConnStr))
{
throw new ArgumentNullException("FreeSqlConnection", "FreeSql主连接字符串不能为空");
}
// 2. 初始化FreeSql(核心:调用UseConnectionString并传入非空值)
var fsql = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.PostgreSQL, sqlConnStr) // 指定数据库类型+连接字符串
.UseAutoSyncStructure(true) // 自动同步实体结构(开发环境可用,生产谨慎)
.UseNoneCommandParameter(true)
.UseNameConvert(NameConvertType.ToLower)
.Build();
// 3. 注册为全局单例(方便依赖注入)
builder.Services.AddSingleton<IFreeSql>(fsql);
//builder.Services.AddSingleton<EquipmentRepository>(new EquipmentRepository(fsql));
//builder.Services.AddSingleton<EquipmentPropRepository>(new EquipmentPropRepository(fsql));
builder.Services.AddSingleton<EquipmentRepository>();
builder.Services.AddSingleton<EquipmentPropRepository>();
builder.Services.AddSingleton<EquipmentTypeRepository>();
builder.Services.AddSingleton<EquipmentTypePropTemplateRepository>();
builder.Services.AddSingleton<EquipmentExecutor>();
// 使用 Serilog 替代默认日志
builder.Host.UseSerilog();
// Add services to the container.
builder.Services.AddControllers();
// 添加 CORS 策略,允许跨域访问(根据需要修改策略)
builder.Services.AddCors(options =>
{
options.AddPolicy("DefaultCorsPolicy", policy =>
{
policy.SetIsOriginAllowed(_ => true)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
});
});
// 添加 SignalR(使用 camelCase JSON 序列化)
builder.Services.AddSignalR().AddJsonProtocol(options =>
{
options.PayloadSerializerOptions.PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase;
});
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
{
Title = "HHRCS API",
Version = "v1",
Description = "长沙华恒机器人控制系统 API"
});
});
// 安装应用配置
builder.InstallApplicationSettings();
// 安装Entity Framework
builder.InstallEntityFramework();
// 安装依赖注入
builder.InstallDependencyInjection();
// 安装 AutoMapper
builder.Services.InstallAutoMapper();
// 安装 Redis
builder.InstallRedis();
// 安装 Mqtt
builder.InstallMqtt();
// 安装过滤器
builder.InstallFilters();
// 安装消息总线 (MassTransit + RabbitMQ)
builder.InstallMessageBus();
// 安装 LanYin 服务
builder.Services.InstallLanYinService();
builder.Services.InstallHttpClient();
// 交通管制服务
builder.Services.InstallerPathService();
// 添加机器人状态推送后台服务
builder.Services.AddHostedService<RobotStatusPushService>();
builder.Services.AddHostedService(provider => provider.GetRequiredService<EquipmentExecutor>());
//builder.Services.AddHostedService<EquipmentExecutor>(
////t =>
////{
//// var mainExecutor = new EquipmentExecutor(t.GetService<EquipmentRepository>(), t.GetService<EquipmentPropRepository>(),t.GetService<EquipmentTypeRepository>(),t.GetService<EquipmentTypePropTemplateRepository>());
//// return mainExecutor;
////}
//);
//调度相关
var ebResult = EquipmentCommunicationHubBuilder.Build("HubBuilder3.x.json");
if (!ebResult.Success)
{
Console.WriteLine("BuilderError:" + ebResult.Msg);
return;
}
var app = builder.Build();
// 自动运行数据库迁移
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
app.Logger.LogInformation("开始初始化数据库...");
var dbContext = services.GetRequiredService<Rcs.Infrastructure.DB.MsSql.AppDbContext>();
EntityFrameworkInstaller.SeedDatabase(dbContext);
app.Logger.LogInformation("✓ 数据库初始化成功完成");
}
catch (Exception ex)
{
app.Logger.LogError(ex, "✗ 数据库初始化失败");
throw;
}
}
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
// 使用 CORS 策略
app.UseCors("DefaultCorsPolicy");
// 配置静态文件服务,允许访问上传的文件
app.UseStaticFiles();
// 配置上传文件的静态访问路径(使用内容根目录确保 Debug 和 Release 模式一致)
var uploadsPath = Path.Combine(app.Environment.ContentRootPath, "uploads");
if (!Directory.Exists(uploadsPath))
{
Directory.CreateDirectory(uploadsPath);
}
app.Logger.LogInformation("静态文件路径: {UploadsPath}", uploadsPath);
app.UseStaticFiles(new Microsoft.AspNetCore.Builder.StaticFileOptions
{
FileProvider = new Microsoft.Extensions.FileProviders.PhysicalFileProvider(uploadsPath),
RequestPath = "/uploads",
OnPrepareResponse = ctx =>
{
// 禁用缓存,确保每次都获取最新文件
ctx.Context.Response.Headers.Append("Cache-Control", "no-cache, no-store, must-revalidate");
ctx.Context.Response.Headers.Append("Pragma", "no-cache");
ctx.Context.Response.Headers.Append("Expires", "0");
// 添加 CORS 头,允许 SVG 图片跨域访问
ctx.Context.Response.Headers.Append("Access-Control-Allow-Origin", "*");
ctx.Context.Response.Headers.Append("Access-Control-Allow-Methods", "GET, OPTIONS");
ctx.Context.Response.Headers.Append("Access-Control-Allow-Headers", "*");
}
});
app.MapControllers();
// 映射 SignalR Hub(支持地图隔离)
app.MapHub<HHRCSHub>("/{mapId}/hubs/HHRCS");
app.Run();
}
finally
{
// 确保 Serilog 日志在程序关闭时正确刷新
Log.CloseAndFlush();
}
namespace Rcs.Api
{
record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
}