add timezone in docker container and force before hangfire start
This commit is contained in:
parent
7ba9a6df5a
commit
772c9482aa
2 changed files with 143 additions and 134 deletions
|
|
@ -1,6 +1,11 @@
|
||||||
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
|
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
|
||||||
|
|
||||||
|
# ตั้งค่า TimeZone ใน Container
|
||||||
|
ENV TZ=Asia/Bangkok
|
||||||
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
EXPOSE 443
|
EXPOSE 443
|
||||||
|
|
|
||||||
|
|
@ -24,163 +24,167 @@ using BMA.EHR.Application.Repositories.Leaves.TimeAttendants;
|
||||||
using BMA.EHR.Leave.Service.Extensions;
|
using BMA.EHR.Leave.Service.Extensions;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
// ตั้ง TimeZone เป็น Asia/Bangkok ในโค้ด
|
||||||
|
var bangkokTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Asia/Bangkok");
|
||||||
|
TimeZoneInfo.ClearCachedData();
|
||||||
|
|
||||||
|
|
||||||
|
var issuer = builder.Configuration["Jwt:Issuer"];
|
||||||
|
var key = builder.Configuration["Jwt:Key"];
|
||||||
|
|
||||||
|
|
||||||
|
IdentityModelEventSource.ShowPII = true;
|
||||||
|
|
||||||
|
builder.Services.AddHttpContextAccessor();
|
||||||
|
|
||||||
|
builder.Services.AddApiVersioning(opt =>
|
||||||
{
|
{
|
||||||
var issuer = builder.Configuration["Jwt:Issuer"];
|
opt.DefaultApiVersion = new ApiVersion(1, 0);
|
||||||
var key = builder.Configuration["Jwt:Key"];
|
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;
|
||||||
|
});
|
||||||
|
|
||||||
IdentityModelEventSource.ShowPII = true;
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
|
||||||
builder.Services.AddHttpContextAccessor();
|
// Authorization
|
||||||
|
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(opt =>
|
||||||
builder.Services.AddApiVersioning(opt =>
|
{
|
||||||
|
opt.SaveToken = true;
|
||||||
|
opt.RequireHttpsMetadata = false; //false for dev
|
||||||
|
opt.Authority = issuer;
|
||||||
|
opt.TokenValidationParameters = new()
|
||||||
{
|
{
|
||||||
opt.DefaultApiVersion = new ApiVersion(1, 0);
|
ValidateIssuer = true,
|
||||||
opt.AssumeDefaultVersionWhenUnspecified = true;
|
ValidateAudience = false,
|
||||||
opt.ReportApiVersions = true;
|
ValidateLifetime = true,
|
||||||
opt.ApiVersionReader = ApiVersionReader.Combine(new UrlSegmentApiVersionReader(),
|
ValidateIssuerSigningKey = true,
|
||||||
new HeaderApiVersionReader("x-api-version"),
|
ValidIssuer = issuer,
|
||||||
new MediaTypeApiVersionReader("x-api-version"));
|
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key))
|
||||||
});
|
};
|
||||||
|
});
|
||||||
|
builder.Services.AddAuthorization();
|
||||||
|
|
||||||
builder.Services.AddVersionedApiExplorer(setup =>
|
// use serilog
|
||||||
{
|
ConfigureLogs();
|
||||||
setup.GroupNameFormat = "'v'VVV";
|
builder.Host.UseSerilog();
|
||||||
setup.SubstituteApiVersionInUrl = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
// Add config CORS
|
||||||
|
builder.Services.AddCors(options => options.AddDefaultPolicy(builder =>
|
||||||
// Authorization
|
{
|
||||||
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(opt =>
|
builder
|
||||||
{
|
.AllowAnyOrigin()
|
||||||
opt.SaveToken = true;
|
.AllowAnyMethod()
|
||||||
opt.RequireHttpsMetadata = false; //false for dev
|
.AllowAnyHeader()
|
||||||
opt.Authority = issuer;
|
.SetIsOriginAllowedToAllowWildcardSubdomains();
|
||||||
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.
|
// Add services to the container.
|
||||||
builder.Services.AddApplication();
|
builder.Services.AddApplication();
|
||||||
builder.Services.AddLeaveApplication();
|
builder.Services.AddLeaveApplication();
|
||||||
builder.Services.AddPersistence(builder.Configuration);
|
builder.Services.AddPersistence(builder.Configuration);
|
||||||
builder.Services.AddLeavePersistence(builder.Configuration);
|
builder.Services.AddLeavePersistence(builder.Configuration);
|
||||||
|
|
||||||
builder.Services.AddHttpClient();
|
builder.Services.AddHttpClient();
|
||||||
|
|
||||||
builder.Services.AddControllers(options =>
|
builder.Services.AddControllers(options =>
|
||||||
{
|
{
|
||||||
options.SuppressAsyncSuffixInActionNames = false;
|
options.SuppressAsyncSuffixInActionNames = false;
|
||||||
})
|
})
|
||||||
.AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
|
.AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
|
||||||
|
|
||||||
builder.Services.AddSwaggerGen();
|
builder.Services.AddSwaggerGen();
|
||||||
builder.Services.ConfigureOptions<ConfigureSwaggerOptions>();
|
builder.Services.ConfigureOptions<ConfigureSwaggerOptions>();
|
||||||
|
|
||||||
builder.Services.AddHealthChecks();
|
builder.Services.AddHealthChecks();
|
||||||
|
|
||||||
builder.Services.AddRabbitMqConnectionPooling(builder.Configuration);
|
builder.Services.AddRabbitMqConnectionPooling(builder.Configuration);
|
||||||
|
|
||||||
// Add Hangfire services.
|
// Add Hangfire services.
|
||||||
var defaultConnection = builder.Configuration.GetConnectionString("DefaultConnection");
|
var defaultConnection = builder.Configuration.GetConnectionString("DefaultConnection");
|
||||||
|
|
||||||
|
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),
|
||||||
|
TablesPrefix = "Hangfire"
|
||||||
|
})));
|
||||||
|
builder.Services.AddHangfireServer();
|
||||||
|
|
||||||
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),
|
|
||||||
TablesPrefix = "Hangfire"
|
|
||||||
})));
|
|
||||||
builder.Services.AddHangfireServer();
|
|
||||||
}
|
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
|
var apiVersionDescriptionProvider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>();
|
||||||
|
|
||||||
|
if (app.Environment.IsDevelopment())
|
||||||
{
|
{
|
||||||
var apiVersionDescriptionProvider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>();
|
app.UseSwagger();
|
||||||
|
app.UseSwaggerUI(options =>
|
||||||
if (app.Environment.IsDevelopment())
|
|
||||||
{
|
{
|
||||||
app.UseSwagger();
|
foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions)
|
||||||
app.UseSwaggerUI(options =>
|
|
||||||
{
|
{
|
||||||
foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions)
|
options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json",
|
||||||
{
|
description.GroupName.ToUpperInvariant());
|
||||||
options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json",
|
}
|
||||||
description.GroupName.ToUpperInvariant());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
app.MapHealthChecks("/health");
|
|
||||||
|
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
|
||||||
app.UseCors();
|
|
||||||
app.UseAuthentication();
|
|
||||||
app.UseAuthorization();
|
|
||||||
app.UseDefaultFiles();
|
|
||||||
app.UseStaticFiles();
|
|
||||||
app.MapControllers();
|
|
||||||
app.UseMiddleware<ErrorHandlerMiddleware>();
|
|
||||||
|
|
||||||
|
|
||||||
app.UseHangfireDashboard("/hangfire", new DashboardOptions()
|
|
||||||
{
|
|
||||||
Authorization = new[] { new CustomAuthorizeFilter() }
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var manager = new RecurringJobManager();
|
|
||||||
if (manager != null)
|
|
||||||
{
|
|
||||||
manager.AddOrUpdate("ปรับปรุงรอบการลงเวลาทำงาน", Job.FromExpression<UserDutyTimeRepository>(x => x.UpdateUserDutyTime()), "0 1 * * *", TimeZoneInfo.FindSystemTimeZoneById("Asia/Bangkok"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply migrations
|
|
||||||
await using var scope = app.Services.CreateAsyncScope();
|
|
||||||
await using var db = scope.ServiceProvider.GetRequiredService<LeaveDbContext>();
|
|
||||||
await db.Database.MigrateAsync();
|
|
||||||
|
|
||||||
// seed default data
|
|
||||||
await LeaveSeeder.SeedLeaveType(app);
|
|
||||||
|
|
||||||
app.Run();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.MapHealthChecks("/health");
|
||||||
|
|
||||||
|
|
||||||
|
app.UseHttpsRedirection();
|
||||||
|
app.UseCors();
|
||||||
|
app.UseAuthentication();
|
||||||
|
app.UseAuthorization();
|
||||||
|
app.UseDefaultFiles();
|
||||||
|
app.UseStaticFiles();
|
||||||
|
app.MapControllers();
|
||||||
|
app.UseMiddleware<ErrorHandlerMiddleware>();
|
||||||
|
|
||||||
|
|
||||||
|
app.UseHangfireDashboard("/hangfire", new DashboardOptions()
|
||||||
|
{
|
||||||
|
Authorization = new[] { new CustomAuthorizeFilter() }
|
||||||
|
});
|
||||||
|
|
||||||
|
var manager = new RecurringJobManager();
|
||||||
|
if (manager != null)
|
||||||
|
{
|
||||||
|
manager.AddOrUpdate("ปรับปรุงรอบการลงเวลาทำงาน", Job.FromExpression<UserDutyTimeRepository>(x => x.UpdateUserDutyTime()), "0 1 * * *", bangkokTimeZone);
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply migrations
|
||||||
|
await using var scope = app.Services.CreateAsyncScope();
|
||||||
|
await using var db = scope.ServiceProvider.GetRequiredService<LeaveDbContext>();
|
||||||
|
await db.Database.MigrateAsync();
|
||||||
|
|
||||||
|
// seed default data
|
||||||
|
await LeaveSeeder.SeedLeaveType(app);
|
||||||
|
|
||||||
|
app.Run();
|
||||||
|
|
||||||
|
|
||||||
void ConfigureLogs()
|
void ConfigureLogs()
|
||||||
{
|
{
|
||||||
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
|
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue