fix 优化本地离线和在线消费处理
This commit is contained in:
36
Src/Dlhis.Middle/Controllers/OAuth2Controller.cs
Normal file
36
Src/Dlhis.Middle/Controllers/OAuth2Controller.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Text;
|
||||
using Dlhis.Middle.Request;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Dlhis.Middle.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// OAuth2认证
|
||||
/// </summary>
|
||||
[Route("api/user/[controller]")]
|
||||
[ApiController]
|
||||
public class OAuth2Controller : ControllerBase
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
public OAuth2Controller(IHttpClientFactory httpClientFactory, IConfiguration configuration)
|
||||
{
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
||||
[HttpPost("clientgrant")]
|
||||
public async Task<object> ClientGrant(ClientGrantRequest request)
|
||||
{
|
||||
var authority = _configuration.GetSection("Authority").Value;
|
||||
|
||||
var httpClient = _httpClientFactory.CreateClient();
|
||||
|
||||
var content = new StringContent($"grant_type=client_credentials&client_id={request.ClientId}&client_secret={request.ClientSecret}&scope={request.Scope}", Encoding.UTF8, "application/x-www-form-urlencoded");
|
||||
var response = await httpClient.PostAsync($"{authority}/connect/token", content);
|
||||
var result = await response.Content.ReadAsStringAsync();
|
||||
return JObject.Parse(result);
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace Dlhis.Middle.Controllers;
|
||||
/// 订单
|
||||
/// </summary>
|
||||
[Authorize]
|
||||
[Route("api/[controller]")]
|
||||
[Route("api/canteen/[controller]")]
|
||||
[ApiController]
|
||||
public class OrdersController : ControllerBase
|
||||
{
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using Dlhis.Entity.Canteen.Entities;
|
||||
|
||||
namespace Dlhis.Middle.Entities
|
||||
namespace Dlhis.Middle.Entities;
|
||||
|
||||
public class LocalBalanceRecordEntity : BalanceRecordEntity
|
||||
{
|
||||
public class LocalBalanceRecordEntity : BalanceRecordEntity
|
||||
{
|
||||
public new int Id { get; set; }
|
||||
}
|
||||
|
||||
public bool IsSync { get; set; }
|
||||
}
|
||||
@@ -1,6 +1,3 @@
|
||||
using Dlhis.Entity.Basic.Entity;
|
||||
using Dlhis.Entity.Device.Entities;
|
||||
using Dlhis.Middle.Entities;
|
||||
using Dlhis.Middle.Services;
|
||||
using Dlhis.Middle.Services.Implements;
|
||||
using Kurisu.AspNetCore.Startup;
|
||||
@@ -49,16 +46,6 @@ public class Startup : DefaultStartup
|
||||
var factory = Configuration.GetSection("Factory").Value;
|
||||
|
||||
var ds = scope.ServiceProvider.GetService<IDataDownloadService>();
|
||||
ds.TruncateAsync().Wait();
|
||||
ds.DownloadAsync<LocalDepartmentEntity>(factory).Wait();
|
||||
ds.DownloadAsync<LocalDeviceEntity>(factory).Wait();
|
||||
ds.DownloadAsync<LocalDeviceRegistryEntity>(factory).Wait();
|
||||
ds.DownloadAsync<LocalBusinessPlaceEntity>(factory).Wait();
|
||||
ds.DownloadAsync<LocalBusinessShiftEntity>(factory).Wait();
|
||||
ds.DownloadAsync<LocalBusinessPlaceShiftRelationshipEntity>(factory).Wait();
|
||||
ds.DownloadAsync<LocalBusinessShiftMealRelationshipEntity>(factory).Wait();
|
||||
|
||||
ds.DownloadAsync<LocalGainfoEntity>(factory).Wait();
|
||||
ds.DownloadAsync<LocalGainfoMealEntity>(factory).Wait();
|
||||
ds.InitAsync(factory).Wait();
|
||||
}
|
||||
}
|
||||
10
Src/Dlhis.Middle/Request/ClientGrantRequest.cs
Normal file
10
Src/Dlhis.Middle/Request/ClientGrantRequest.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Dlhis.Middle.Request;
|
||||
|
||||
public class ClientGrantRequest
|
||||
{
|
||||
public string ClientId { get; set; }
|
||||
|
||||
public string ClientSecret { get; set; }
|
||||
|
||||
public string Scope { get; set; } = "yikatong";
|
||||
}
|
||||
@@ -2,7 +2,11 @@ namespace Dlhis.Middle.Services;
|
||||
|
||||
public interface IDataDownloadService : IScopeDependency
|
||||
{
|
||||
Task InitAsync(string factory);
|
||||
|
||||
Task DownloadAsync<T>(string factory) where T : class, new();
|
||||
|
||||
Task TruncateAsync();
|
||||
|
||||
Task DownloadGainfosAsync(string factory);
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
using System.Net.Http.Headers;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Dlhis.Middle.Entities;
|
||||
using Dlhis.Middle.Response;
|
||||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
|
||||
using Kurisu.AspNetCore.UnifyResultAndValidation;
|
||||
using Kurisu.AspNetCore.Utils.Extensions;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Newtonsoft.Json;
|
||||
using SqlSugar;
|
||||
|
||||
namespace Dlhis.Middle.Services.Implements;
|
||||
|
||||
public class BalanceRecordCheckBackgroundService : BackgroundService
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ILogger<BalanceRecordCheckBackgroundService> _logger;
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly IHealthCheckService _healthCheckService;
|
||||
private readonly string _factory;
|
||||
private readonly string _hostName;
|
||||
|
||||
public BalanceRecordCheckBackgroundService(IServiceProvider serviceProvider,
|
||||
ILogger<BalanceRecordCheckBackgroundService> logger,
|
||||
IMemoryCache memoryCache,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
IHealthCheckService healthCheckService,
|
||||
IConfiguration configuration)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_logger = logger;
|
||||
_memoryCache = memoryCache;
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_healthCheckService = healthCheckService;
|
||||
_factory = configuration.GetSection("Factory").Value;
|
||||
_hostName = configuration.GetSection("HostName").Value;
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
if (!_healthCheckService.GetIsOffline())
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
|
||||
using (var scope = _serviceProvider.CreateScope())
|
||||
{
|
||||
try
|
||||
{
|
||||
var db = scope.ServiceProvider.GetService<IDbContext>();
|
||||
var ds = scope.ServiceProvider.GetService<IDataDownloadService>();
|
||||
var balanceRecords = await db.Queryable<LocalBalanceRecordEntity>().Where(x => !x.IsSync).ToListAsync(stoppingToken);
|
||||
if (balanceRecords.Any())
|
||||
{
|
||||
foreach (var balanceRecord in balanceRecords)
|
||||
{
|
||||
await db.Client.Ado.BeginTranAsync();
|
||||
try
|
||||
{
|
||||
balanceRecord.IsSync = true;
|
||||
await db.UpdateAsync(balanceRecord);
|
||||
|
||||
var r = await UploadAsync(balanceRecord);
|
||||
if (r.Code == ApiStateCode.Success)
|
||||
{
|
||||
var d = r.Data;
|
||||
var balance = decimal.Parse(d.Balance);
|
||||
await db.Updateable<LocalGainfoMealEntity>()
|
||||
.SetColumns(x => x.Balance == balance)
|
||||
.Where(x => x.UserCode == d.UserCode)
|
||||
.ExecuteCommandAsync(stoppingToken);
|
||||
|
||||
await db.Client.Ado.CommitTranAsync();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "{factory}上传离线消费失败:{message}", _factory, e.Message);
|
||||
await db.Client.Ado.RollbackTranAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (now.Hour == 4 && now.Minute == 1 && !_healthCheckService.GetIsOffline() && !await db.Queryable<LocalBalanceRecordEntity>().Where(x => !x.IsSync).AnyAsync())
|
||||
{
|
||||
await ds.DownloadGainfosAsync(_factory);
|
||||
}
|
||||
else if (now.Hour == 15 && now.Minute == 1 && !_healthCheckService.GetIsOffline() && !await db.Queryable<LocalBalanceRecordEntity>().Where(x => !x.IsSync).AnyAsync())
|
||||
{
|
||||
await ds.DownloadGainfosAsync(_factory);
|
||||
}
|
||||
else if (now.Hour == 20 && now.Minute == 1 && !_healthCheckService.GetIsOffline() && !await db.Queryable<LocalBalanceRecordEntity>().Where(x => !x.IsSync).AnyAsync())
|
||||
{
|
||||
await ds.DownloadGainfosAsync(_factory);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "{factory}同步离线数据失败:{message}", _factory, e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await Task.Delay(60 * 1000, stoppingToken);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<DefaultApiResult<OrderResultResponse>> UploadAsync(LocalBalanceRecordEntity entity)
|
||||
{
|
||||
var token = await AuthAsync();
|
||||
|
||||
var httpClient = _httpClientFactory.CreateClient("face");
|
||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
||||
|
||||
var url = $"https://{_hostName}/api/canteen/middle/upload";
|
||||
|
||||
var json = entity.ToJson();
|
||||
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
||||
|
||||
var response = await httpClient.PostAsync(url, content);
|
||||
var responseJson = await response.Content.ReadAsStringAsync();
|
||||
return responseJson.ToObject<DefaultApiResult<OrderResultResponse>>();
|
||||
}
|
||||
|
||||
private async Task<string> AuthAsync()
|
||||
{
|
||||
var httpClient = _httpClientFactory.CreateClient("face");
|
||||
|
||||
if (_memoryCache.TryGetValue("token", out string token)) return token;
|
||||
|
||||
var tokenResponse = await httpClient.PostAsync($"https://{_hostName}/api/User/OAuth2/clientgrant", new StringContent(JsonConvert.SerializeObject(new
|
||||
{
|
||||
ClientId = "e569c2aaa98e300c",
|
||||
ClientSecret = "6184d8979fc48105"
|
||||
}), Encoding.UTF8, "application/json"));
|
||||
|
||||
var tokenJson = await tokenResponse.Content.ReadAsStringAsync();
|
||||
var tokenInfo = JsonConvert.DeserializeObject<DefaultApiResult<TokenResponse>>(tokenJson);
|
||||
|
||||
token = tokenInfo.Data.AccessToken;
|
||||
|
||||
_memoryCache.Set("token", token, TimeSpan.FromSeconds(tokenInfo.Data.Expires));
|
||||
|
||||
return token;
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,31 @@ public class DataDownloadService : IDataDownloadService
|
||||
_hostName = configuration.GetSection("HostName").Value;
|
||||
}
|
||||
|
||||
public async Task InitAsync(string factory)
|
||||
{
|
||||
await TruncateAsync();
|
||||
|
||||
await DownloadAsync<LocalDepartmentEntity>(factory);
|
||||
await DownloadAsync<LocalDeviceEntity>(factory);
|
||||
await DownloadAsync<LocalDeviceRegistryEntity>(factory);
|
||||
|
||||
await DownloadAsync<LocalBusinessPlaceEntity>(factory);
|
||||
await DownloadAsync<LocalBusinessShiftEntity>(factory);
|
||||
await DownloadAsync<LocalBusinessPlaceShiftRelationshipEntity>(factory);
|
||||
|
||||
await DownloadAsync<LocalBusinessShiftMealRelationshipEntity>(factory);
|
||||
|
||||
if (!await _dbContext.Queryable<LocalGainfoEntity>().AnyAsync())
|
||||
{
|
||||
await DownloadAsync<LocalGainfoEntity>(factory);
|
||||
}
|
||||
|
||||
if (!await _dbContext.Queryable<LocalGainfoMealEntity>().AnyAsync())
|
||||
{
|
||||
await DownloadAsync<LocalGainfoMealEntity>(factory);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DownloadAsync<T>(string factory) where T : class, new()
|
||||
{
|
||||
var token = await AuthAsync();
|
||||
@@ -37,7 +62,7 @@ public class DataDownloadService : IDataDownloadService
|
||||
|
||||
var url = $"https://{_hostName}/api/common/SysData/download";
|
||||
#if DEBUG
|
||||
url = $"http://localhost:5001/api/SysData/download";
|
||||
url = "http://localhost:5001/api/SysData/download";
|
||||
#endif
|
||||
|
||||
var requestUrl = QueryHelpers.AddQueryString(url, new Dictionary<string, string>
|
||||
@@ -62,8 +87,29 @@ public class DataDownloadService : IDataDownloadService
|
||||
await _dbContext.Client.Deleteable<LocalBusinessShiftEntity>().ExecuteCommandAsync();
|
||||
await _dbContext.Client.Deleteable<LocalBusinessPlaceShiftRelationshipEntity>().ExecuteCommandAsync();
|
||||
await _dbContext.Client.Deleteable<LocalBusinessShiftMealRelationshipEntity>().ExecuteCommandAsync();
|
||||
|
||||
//await _dbContext.Client.Deleteable<LocalGainfoEntity>().ExecuteCommandAsync();
|
||||
//await _dbContext.Client.Deleteable<LocalGainfoMealEntity>().ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task DownloadGainfosAsync(string factory)
|
||||
{
|
||||
await _dbContext.Client.Ado.BeginTranAsync();
|
||||
try
|
||||
{
|
||||
await _dbContext.Client.Deleteable<LocalGainfoEntity>().ExecuteCommandAsync();
|
||||
await _dbContext.Client.Deleteable<LocalGainfoMealEntity>().ExecuteCommandAsync();
|
||||
|
||||
await DownloadAsync<LocalGainfoEntity>(factory);
|
||||
await DownloadAsync<LocalGainfoMealEntity>(factory);
|
||||
|
||||
await _dbContext.Client.Ado.CommitTranAsync();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await _dbContext.Client.Ado.RollbackTranAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string> AuthAsync()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Dlhis.Entity.Canteen.Entities;
|
||||
using Dlhis.Entity.Canteen.Enums;
|
||||
using Dlhis.Entity.Device.Entities;
|
||||
using Dlhis.Middle.Entities;
|
||||
using Kurisu.AspNetCore.Utils;
|
||||
using Kurisu.AspNetCore.Utils.Extensions;
|
||||
using Mapster;
|
||||
@@ -37,14 +38,20 @@ public class OrderService : IOrderService
|
||||
{
|
||||
if (await _remoteOrderService.AbleRemoteCallAsync())
|
||||
{
|
||||
return await _remoteOrderService.AddAsync(request);
|
||||
var remoteResult = await _remoteOrderService.AddAsync(request);
|
||||
var d = remoteResult.Data;
|
||||
var balance = decimal.Parse(d.Balance);
|
||||
await _dbContext.Updateable<LocalGainfoMealEntity>()
|
||||
.SetColumns(x => x.Balance == balance)
|
||||
.Where(x => x.UserCode == d.UserCode)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
//尝试匹配userId
|
||||
_ = long.TryParse(request.UserUniqueNo, out var userId);
|
||||
|
||||
//根据档案号
|
||||
var gainfo = await _dbContext.Queryable<GainfoEntity>()
|
||||
var gainfo = await _dbContext.Queryable<LocalGainfoEntity>()
|
||||
.Where(x => x.Code == request.UserUniqueNo || x.Id == userId || x.CardNo == request.UserUniqueNo)
|
||||
.FirstAsync();
|
||||
|
||||
@@ -54,7 +61,7 @@ public class OrderService : IOrderService
|
||||
|
||||
try
|
||||
{
|
||||
(await _dbContext.Queryable<GainfoMealEntity>().Where(x => x.UserNo == gainfo.No).AnyAsync())
|
||||
(await _dbContext.Queryable<LocalGainfoMealEntity>().Where(x => x.UserNo == gainfo.No).AnyAsync())
|
||||
.ThrowIfFalse("余额不足,无法消费");
|
||||
|
||||
await ConsumeAsync(request.Adapt<ConsumeRequest>(), gainfo);
|
||||
@@ -95,17 +102,17 @@ public class OrderService : IOrderService
|
||||
/// <param name="request"></param>
|
||||
/// <param name="gainfo"></param>
|
||||
/// <returns></returns>
|
||||
private async Task ConsumeAsync(ConsumeRequest request, GainfoEntity gainfo)
|
||||
private async Task ConsumeAsync(ConsumeRequest request, LocalGainfoEntity gainfo)
|
||||
{
|
||||
var registry = await _dbContext.Queryable<DeviceRegistryEntity>().Where(x => x.DeviceUniqueNo == request.DeviceUniqueNo).SingleAsync();
|
||||
var registry = await _dbContext.Queryable<LocalDeviceRegistryEntity>().Where(x => x.DeviceUniqueNo == request.DeviceUniqueNo).SingleAsync();
|
||||
registry.ThrowIfNull("设备尚未登记");
|
||||
|
||||
var device = await _dbContext.Queryable<DeviceEntity>().Where(x => x.UniqueNo == request.DeviceUniqueNo).SingleAsync();
|
||||
var device = await _dbContext.Queryable<LocalDeviceEntity>().Where(x => x.UniqueNo == request.DeviceUniqueNo).SingleAsync();
|
||||
device.ThrowIfNull("设备尚未登记");
|
||||
device.Enable.ThrowIfFalse("设备已被停用");
|
||||
|
||||
var businessPlaceInfo = await _dbContext.Queryable<BusinessPlaceEntity>()
|
||||
.LeftJoin<BusinessPlaceShiftRelationshipEntity>((x, sr) => x.Code == sr.PlaceCode)
|
||||
var businessPlaceInfo = await _dbContext.Queryable<LocalBusinessPlaceEntity>()
|
||||
.LeftJoin<LocalBusinessPlaceShiftRelationshipEntity>((x, sr) => x.Code == sr.PlaceCode)
|
||||
.Where(x => x.Code == registry.BusinessPlaceCode)
|
||||
.Select((x, sr) => new
|
||||
{
|
||||
@@ -117,7 +124,7 @@ public class OrderService : IOrderService
|
||||
businessPlaceInfo.ThrowIfNull("设备尚未登记营业点");
|
||||
|
||||
//获取当前消费餐次
|
||||
var shifts = await _dbContext.Queryable<BusinessShiftMealRelationshipEntity>().Where(x => x.ShiftCode == businessPlaceInfo.ShiftCode).ToListAsync();
|
||||
var shifts = await _dbContext.Queryable<LocalBusinessShiftMealRelationshipEntity>().Where(x => x.ShiftCode == businessPlaceInfo.ShiftCode).ToListAsync();
|
||||
shifts.ThrowIfEmpty("营业点餐次尚未设置");
|
||||
|
||||
var shift = shifts.FirstOrDefault(x => new TimePeriod
|
||||
@@ -129,7 +136,7 @@ public class OrderService : IOrderService
|
||||
|
||||
var costDate = await GetCostDateAsync(shift, request.CostDateTime);
|
||||
|
||||
var balanceRecord = new BalanceRecordEntity
|
||||
var balanceRecord = new LocalBalanceRecordEntity
|
||||
{
|
||||
// RequestJson = request.ToJson(),
|
||||
// ThirdNo = request.ThirdNo,
|
||||
@@ -178,13 +185,13 @@ public class OrderService : IOrderService
|
||||
{
|
||||
if (!allowNoBalance)
|
||||
{
|
||||
var gainfoMeal = await _dbContext.Queryable<GainfoMealEntity>().Where(x => x.UserNo == balanceRecord.UserNo).SingleAsync();
|
||||
var gainfoMeal = await _dbContext.Queryable<LocalGainfoMealEntity>().Where(x => x.UserNo == balanceRecord.UserNo).SingleAsync();
|
||||
//金额+-
|
||||
gainfoMeal.Balance += balanceRecord.Amount;
|
||||
|
||||
(gainfoMeal.Balance < 0).ThrowIfTrue("余额不足,无法消费");
|
||||
|
||||
await _dbContext.Updateable<GainfoMealEntity>()
|
||||
await _dbContext.Updateable<LocalGainfoMealEntity>()
|
||||
.SetColumns(x => x.Balance == gainfoMeal.Balance)
|
||||
.SetColumns(x => x.Version == x.Version + 1)
|
||||
.SetColumns(x => x.ModifiedTime == DateTime.Now)
|
||||
@@ -230,13 +237,13 @@ public class OrderService : IOrderService
|
||||
/// <param name="order"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="UserFriendlyException"></exception>
|
||||
private async Task Verify(BalanceRecordEntity order)
|
||||
private async Task Verify(LocalBalanceRecordEntity order)
|
||||
{
|
||||
var beginOfDay = DateTime.Today;
|
||||
var endOfDay = beginOfDay.AddDays(1).AddSeconds(-1);
|
||||
|
||||
//今天所有消费记录
|
||||
var todayAllBalanceRecords = await _dbContext.Queryable<BalanceRecordEntity>()
|
||||
var todayAllBalanceRecords = await _dbContext.Queryable<LocalBalanceRecordEntity>()
|
||||
.Where(x => x.UserNo == order.UserNo)
|
||||
.Where(x => x.Type == BalanceRecordTypeEnumType.Out)
|
||||
.Where(x => x.Status == BalanceRecordStatusEnumType.Valid)
|
||||
@@ -244,7 +251,7 @@ public class OrderService : IOrderService
|
||||
.ToListAsync();
|
||||
|
||||
//超市营业点
|
||||
var supermarketCodes = await _dbContext.Queryable<BusinessPlaceEntity>()
|
||||
var supermarketCodes = await _dbContext.Queryable<LocalBusinessPlaceEntity>()
|
||||
.Where(x => x.Catalog == CanteenBusinessPlaceCatalogEnumType.Supermarket)
|
||||
.Select(x => x.Code)
|
||||
.ToListAsync();
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
"SlowSqlTime": 1,
|
||||
"EnableSqlLog": false
|
||||
},
|
||||
"Authority": "https://face.jinkosolar.com",
|
||||
"Factory": "",
|
||||
"HostName": "",
|
||||
"HostName": "face.jinkosolar.com",
|
||||
"AllowedHosts": "*",
|
||||
"Serilog": {
|
||||
"MinimumLevel": {
|
||||
|
||||
Reference in New Issue
Block a user