265 lines
11 KiB
C#
265 lines
11 KiB
C#
using BMA.EHR.Application;
|
|
using BMA.EHR.Application.Repositories.Reports;
|
|
using BMA.EHR.Domain.Middlewares;
|
|
using BMA.EHR.Infrastructure;
|
|
using BMA.EHR.Infrastructure.Persistence;
|
|
using BMA.EHR.Insignia.Service;
|
|
using BMA.EHR.Insignia.Service.Filters;
|
|
using BMA.EHR.Insignia.Service.Services;
|
|
using Hangfire;
|
|
using Hangfire.Common;
|
|
using Hangfire.MySql;
|
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
|
using Microsoft.AspNetCore.Mvc.Versioning;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.IdentityModel.Logging;
|
|
using Microsoft.IdentityModel.Tokens;
|
|
using Serilog;
|
|
using Serilog.Exceptions;
|
|
using Serilog.Sinks.Elasticsearch;
|
|
using System.Text;
|
|
using System.Transactions;
|
|
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
{
|
|
var issuer = builder.Configuration["Jwt:Issuer"];
|
|
var key = builder.Configuration["Jwt:Key"];
|
|
|
|
IdentityModelEventSource.ShowPII = true;
|
|
|
|
builder.Services.AddHttpContextAccessor();
|
|
|
|
builder.Services.AddApiVersioning(opt =>
|
|
{
|
|
opt.DefaultApiVersion = new ApiVersion(1, 0);
|
|
opt.AssumeDefaultVersionWhenUnspecified = true;
|
|
opt.ReportApiVersions = true;
|
|
opt.ApiVersionReader = ApiVersionReader.Combine(new UrlSegmentApiVersionReader(),
|
|
new HeaderApiVersionReader("x-api-version"),
|
|
new MediaTypeApiVersionReader("x-api-version"));
|
|
});
|
|
|
|
builder.Services.AddVersionedApiExplorer(setup =>
|
|
{
|
|
setup.GroupNameFormat = "'v'VVV";
|
|
setup.SubstituteApiVersionInUrl = true;
|
|
});
|
|
|
|
builder.Services.AddEndpointsApiExplorer();
|
|
|
|
// Authorization
|
|
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(opt =>
|
|
{
|
|
opt.RequireHttpsMetadata = false; //false for dev
|
|
opt.Authority = issuer;
|
|
opt.TokenValidationParameters = new()
|
|
{
|
|
ValidateIssuer = true,
|
|
ValidateAudience = false,
|
|
ValidateLifetime = true,
|
|
ValidateIssuerSigningKey = true,
|
|
ValidIssuer = issuer,
|
|
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key))
|
|
};
|
|
});
|
|
builder.Services.AddAuthorization();
|
|
|
|
// use serilog
|
|
//ConfigureLogs();
|
|
//builder.Host.UseSerilog();
|
|
|
|
// Add config CORS
|
|
builder.Services.AddCors(options => options.AddDefaultPolicy(builder =>
|
|
{
|
|
builder
|
|
.AllowAnyOrigin()
|
|
.AllowAnyMethod()
|
|
.AllowAnyHeader()
|
|
.SetIsOriginAllowedToAllowWildcardSubdomains();
|
|
}));
|
|
|
|
|
|
// Add services to the container.
|
|
builder.Services.AddApplication();
|
|
builder.Services.AddPersistence(builder.Configuration);
|
|
|
|
builder.Services.AddLeaveApplication();
|
|
builder.Services.AddLeavePersistence(builder.Configuration);
|
|
|
|
builder.Services.AddSingleton<IBackgroundTaskQueue, BackgroundTaskQueue>();
|
|
builder.Services.AddHostedService<InsigniaRequestProcessService>();
|
|
|
|
|
|
|
|
builder.Services.AddControllers(options =>
|
|
{
|
|
options.SuppressAsyncSuffixInActionNames = false;
|
|
})
|
|
.AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
|
|
|
|
builder.Services.AddSwaggerGen();
|
|
builder.Services.ConfigureOptions<ConfigureSwaggerOptions>();
|
|
|
|
// Register DbContext
|
|
var defaultConnection = builder.Configuration.GetConnectionString("DefaultConnection");
|
|
builder.Services.AddDbContext<ApplicationDBContext>(options =>
|
|
options.UseMySql(defaultConnection, ServerVersion.AutoDetect(defaultConnection)), ServiceLifetime.Transient);
|
|
builder.Services.AddHealthChecks();
|
|
// Add Hangfire services.
|
|
builder.Services.AddHangfire(configuration => configuration
|
|
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
|
|
.UseSimpleAssemblyNameTypeSerializer()
|
|
.UseRecommendedSerializerSettings()
|
|
.UseStorage(
|
|
new MySqlStorage(
|
|
defaultConnection,
|
|
new MySqlStorageOptions
|
|
{
|
|
TransactionIsolationLevel = IsolationLevel.ReadCommitted,
|
|
QueuePollInterval = TimeSpan.FromSeconds(15),
|
|
JobExpirationCheckInterval = TimeSpan.FromHours(1),
|
|
CountersAggregateInterval = TimeSpan.FromMinutes(5),
|
|
PrepareSchemaIfNecessary = true,
|
|
DashboardJobListLimit = 50000,
|
|
TransactionTimeout = TimeSpan.FromMinutes(1),
|
|
InvisibilityTimeout = TimeSpan.FromHours(3),
|
|
TablesPrefix = "Hangfire_Insignia"
|
|
})));
|
|
builder.Services.AddHangfireServer(options =>
|
|
{
|
|
options.ServerName = "Insignia-Server"; // ← ระบุชื่อ server
|
|
options.WorkerCount = 5; // ←
|
|
options.Queues = new[] { "insignia","default" }; // ← worker จะรันเฉพาะ queue "insignia"
|
|
});
|
|
|
|
|
|
// RabbitMQ
|
|
//builder.Services.AddTransient<RabbitMQConsumer>(provider =>
|
|
//{
|
|
// var serviceScopeFactory = provider.GetRequiredService<IServiceScopeFactory>();
|
|
// var userRepo = provider.GetRequiredService<UserProfileRepository>();
|
|
// var insigniaRepo = provider.GetRequiredService<InsigniaPeriodsRepository>();
|
|
// var httpContext = provider.GetRequiredService<IHttpContextAccessor>();
|
|
// var config = provider.GetRequiredService<IConfiguration>();
|
|
|
|
// return new RabbitMQConsumer(userRepo, insigniaRepo, httpContext, serviceScopeFactory, config);
|
|
//});
|
|
}
|
|
|
|
var app = builder.Build();
|
|
{
|
|
var apiVersionDescriptionProvider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>();
|
|
|
|
if (app.Environment.IsDevelopment())
|
|
{
|
|
app.UseSwagger();
|
|
app.UseSwaggerUI(options =>
|
|
{
|
|
foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions)
|
|
{
|
|
options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json",
|
|
description.GroupName.ToUpperInvariant());
|
|
}
|
|
});
|
|
}
|
|
|
|
app.MapHealthChecks("/health");
|
|
|
|
|
|
|
|
|
|
app.UseHttpsRedirection();
|
|
app.UseCors();
|
|
app.UseMiddleware<CombinedErrorHandlerAndLoggingMiddleware>();
|
|
app.UseAuthentication();
|
|
app.UseAuthorization();
|
|
app.UseDefaultFiles();
|
|
app.UseStaticFiles();
|
|
app.MapControllers();
|
|
// app.UseMiddleware<ErrorHandlerMiddleware>();
|
|
// app.UseMiddleware<RequestLoggingMiddleware>();
|
|
app.UseHangfireDashboard("/hangfire", new DashboardOptions()
|
|
{
|
|
Authorization = new[] { new CustomAuthorizeFilter() }
|
|
});
|
|
var manager = new RecurringJobManager();
|
|
if (manager != null)
|
|
{
|
|
manager.AddOrUpdate("แจ้งเตือนรอบเครื่องราชฯ", Job.FromExpression<InsigniaReportRepository>(x => x.NotifyInsignia()), Cron.Daily(Int32.Parse(builder.Configuration["KeycloakCron:Hour"]), Int32.Parse(builder.Configuration["KeycloakCron:Minute"])), TimeZoneInfo.Local);
|
|
manager.AddOrUpdate("ล็อกข้อมูลรอบเครื่องราชฯ", Job.FromExpression<InsigniaReportRepository>(x => x.LockInsignia()), Cron.Daily(Int32.Parse(builder.Configuration["KeycloakCron:Hour"]), Int32.Parse(builder.Configuration["KeycloakCron:Minute"])), TimeZoneInfo.Local);
|
|
//manager.AddOrUpdate("คำนวนผู้ได้รับเครื่องราชฯ", () => CalculateInsigniaRequestBkkByType("officer"), Cron.Daily(Int32.Parse(builder.Configuration["KeycloakCron:Hour"]), Int32.Parse(builder.Configuration["KeycloakCron:Minute"])), TimeZoneInfo.Local);
|
|
//manager.AddOrUpdate("คำนวนผู้ได้รับเครื่องราชฯ Employee", Job.FromExpression<InsigniaReportRepository>(x => x.CalInsigniaRequestBkkByType("employee")), Cron.Daily(Int32.Parse(builder.Configuration["KeycloakCron:Hour"]), Int32.Parse(builder.Configuration["KeycloakCron:Minute"])), TimeZoneInfo.Local);
|
|
}
|
|
|
|
RecurringJob.AddOrUpdate<InsigniaReportRepository>(
|
|
"คำนวนผู้ได้รับเครื่องราชฯ",
|
|
x => x.CalculateInsigniaRequestBkkByType("officer"),
|
|
Cron.Daily(Int32.Parse(builder.Configuration["KeycloakCron:Hour"]) - 5,
|
|
Int32.Parse(builder.Configuration["KeycloakCron:Minute"])),
|
|
new RecurringJobOptions
|
|
{
|
|
TimeZone = TimeZoneInfo.Local,
|
|
QueueName = "insignia" // ← กำหนด queue
|
|
}
|
|
);
|
|
|
|
RecurringJob.AddOrUpdate<InsigniaReportRepository>(
|
|
"คำนวนผู้ได้รับเครื่องราชฯ Employee",
|
|
x => x.CalculateInsigniaRequestBkkByType("employee"),
|
|
Cron.Daily(Int32.Parse(builder.Configuration["KeycloakCron:Hour"]) - 4,
|
|
Int32.Parse(builder.Configuration["KeycloakCron:Minute"])),
|
|
new RecurringJobOptions
|
|
{
|
|
TimeZone = TimeZoneInfo.Local,
|
|
QueueName = "insignia" // ← กำหนด queue
|
|
}
|
|
);
|
|
|
|
// apply migrations
|
|
await using var scope = app.Services.CreateAsyncScope();
|
|
await using var db = scope.ServiceProvider.GetRequiredService<ApplicationDBContext>();
|
|
await db.Database.MigrateAsync();
|
|
|
|
//var rabbitMQConsumer = app.Services.GetRequiredService<RabbitMQConsumer>();
|
|
//rabbitMQConsumer.StartReceiving();
|
|
|
|
|
|
|
|
app.Run();
|
|
}
|
|
|
|
|
|
|
|
void ConfigureLogs()
|
|
{
|
|
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
|
|
var configuration = new ConfigurationBuilder()
|
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
|
.AddJsonFile(
|
|
$"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json",
|
|
optional: true)
|
|
.Build();
|
|
|
|
Log.Logger = new LoggerConfiguration()
|
|
.Enrich.FromLogContext()
|
|
.MinimumLevel.Error()
|
|
.WriteTo.Console()
|
|
.Enrich.WithExceptionDetails()
|
|
.WriteTo.Elasticsearch(ConfigureElasticSink(configuration, environment ?? ""))
|
|
.Enrich.WithProperty("Environment", environment)
|
|
.ReadFrom.Configuration(configuration)
|
|
.CreateLogger();
|
|
}
|
|
|
|
ElasticsearchSinkOptions ConfigureElasticSink(IConfigurationRoot configuration, string environment)
|
|
{
|
|
return new ElasticsearchSinkOptions(new Uri(configuration["ElasticConfiguration:Uri"] ?? ""))
|
|
{
|
|
AutoRegisterTemplate = true,
|
|
IndexFormat = "bma-ehr-log-index",
|
|
//IndexFormat = $"{Assembly.GetExecutingAssembly()?.GetName()?.Name?.ToLower().Replace(".", "-")}-{environment?.ToLower().Replace(".", "-")}"
|
|
};
|
|
}
|
|
|