|
|
using Autofac.Extensions.DependencyInjection;
|
|
|
using Lierda.WPFHelper;
|
|
|
using Microsoft.AspNetCore.Hosting;
|
|
|
using Microsoft.Extensions.Configuration;
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
using Microsoft.Extensions.Hosting;
|
|
|
using Serilog;
|
|
|
using SlnMesnac.Config;
|
|
|
using SlnMesnac.Plc;
|
|
|
using SlnMesnac.Rfid;
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Windows;
|
|
|
|
|
|
namespace SlnMesnac.WPF
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// Interaction logic for App.xaml
|
|
|
/// </summary>
|
|
|
public partial class App : Application
|
|
|
{
|
|
|
private System.Threading.Mutex? mutex = null;
|
|
|
private LierdaCracker cracker = new LierdaCracker();
|
|
|
public static IServiceProvider? ServiceProvider = null;
|
|
|
private static IHost? host;
|
|
|
private AppConfig appConfig;
|
|
|
// Startup事件
|
|
|
protected override async void OnStartup(StartupEventArgs e)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
bool ret;
|
|
|
//mutex = new System.Threading.Mutex(true, System.Diagnostics.Process.GetCurrentProcess().ProcessName, out ret);
|
|
|
//if (!ret)
|
|
|
//{
|
|
|
// MessageBox.Show("应用程序已开启,禁止重复运行");
|
|
|
// Environment.Exit(0);
|
|
|
//}
|
|
|
|
|
|
cracker.Cracker(100); //设置GC回收间隔
|
|
|
|
|
|
base.OnStartup(e);
|
|
|
//var host = CreateHostBuilder(e.Args).Build();//生成宿主。
|
|
|
|
|
|
//ServiceProvider = host.Services;
|
|
|
|
|
|
//await host.StartAsync();
|
|
|
var instanceId = GetInstanceId(e.Args);
|
|
|
// 创建完全独立的Host构建器
|
|
|
host = CreateHostBuilder(e.Args, instanceId).Build();
|
|
|
|
|
|
// 预先验证服务
|
|
|
using (var scope = host.Services.CreateScope())
|
|
|
{
|
|
|
ServiceProvider = scope.ServiceProvider;
|
|
|
|
|
|
try
|
|
|
{
|
|
|
|
|
|
//serilogHelper = services.GetRequiredService<SerilogHelper>();
|
|
|
//serilogHelper.Info($"启动服务");
|
|
|
//var appConfig = services.GetRequiredService<AppConfig>();
|
|
|
appConfig = host.Services.GetService<AppConfig>();
|
|
|
|
|
|
// 强制设置实例ID到配置对象
|
|
|
SetInstanceSpecificConfiguration(appConfig, instanceId);
|
|
|
|
|
|
//serilogHelper.Info($"实例 {instanceId} 服务初始化完成");
|
|
|
Console.WriteLine($"实例 {instanceId} 服务初始化完成");
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
Console.WriteLine($"实例 {instanceId} 服务初始化失败: {ex.Message}");
|
|
|
//serilogHelper.Info($"详细错误: {ex}");
|
|
|
}
|
|
|
}
|
|
|
//await host.StartAsync();
|
|
|
var hostTask = host.RunAsync();
|
|
|
var logPath = $"{appConfig.logPath}/Logs/{DateTime.UtcNow:yyyy-MM-dd}/";
|
|
|
Log.Information($"系统初始化完成,日志存放路径:{appConfig.logPath}");
|
|
|
}
|
|
|
catch (Exception exception)
|
|
|
{
|
|
|
Console.WriteLine(exception);
|
|
|
throw;
|
|
|
}
|
|
|
|
|
|
|
|
|
}
|
|
|
private static void SetInstanceSpecificConfiguration(AppConfig appConfig, string instanceId)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
Console.WriteLine($"为实例 {instanceId} 设置特定配置...");
|
|
|
|
|
|
// 使用反射设置所有可能的配置属性
|
|
|
var configType = appConfig.GetType();
|
|
|
var properties = configType.GetProperties();
|
|
|
|
|
|
foreach (var property in properties)
|
|
|
{
|
|
|
if (property.CanWrite)
|
|
|
{
|
|
|
var value = property.GetValue(appConfig);
|
|
|
if (value is string stringValue)
|
|
|
{
|
|
|
// 替换路径中的占位符
|
|
|
if (stringValue.Contains("{Instance}") ||
|
|
|
stringValue.Contains("{instance}"))
|
|
|
{
|
|
|
var newValue = stringValue
|
|
|
.Replace("{Instance}", instanceId)
|
|
|
.Replace("{instance}", instanceId);
|
|
|
property.SetValue(appConfig, newValue);
|
|
|
Console.WriteLine($" 更新 {property.Name}: {newValue}");
|
|
|
}
|
|
|
else if (IsPathProperty(property.Name) &&
|
|
|
!stringValue.Contains(instanceId))
|
|
|
{
|
|
|
// 为路径属性添加实例ID
|
|
|
var newValue = $"{stringValue}_Instance{instanceId}";
|
|
|
property.SetValue(appConfig, newValue);
|
|
|
Console.WriteLine($" 更新 {property.Name}: {newValue}");
|
|
|
}
|
|
|
}
|
|
|
else if (property.PropertyType == typeof(int) &&
|
|
|
IsPortProperty(property.Name))
|
|
|
{
|
|
|
// 调整端口号
|
|
|
var basePort = (int)value;
|
|
|
var newPort = basePort + (int.Parse(instanceId) - 1) * 10;
|
|
|
property.SetValue(appConfig, newPort);
|
|
|
Console.WriteLine($" 更新 {property.Name}: {newPort}");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
Console.WriteLine($"设置实例配置时出错: {ex.Message}");
|
|
|
//serilogHelper?.Info($"设置实例配置时出错: {ex.Message}");
|
|
|
}
|
|
|
}
|
|
|
private static bool IsPortProperty(string propertyName)
|
|
|
{
|
|
|
return propertyName.ToLower().Contains("port");
|
|
|
}
|
|
|
private static bool IsPathProperty(string propertyName)
|
|
|
{
|
|
|
return propertyName.ToLower().Contains("path") ||
|
|
|
propertyName.ToLower().Contains("dir") ||
|
|
|
propertyName.ToLower().Contains("file");
|
|
|
}
|
|
|
public static IHostBuilder CreateHostBuilder(string[] args, string instanceId) =>
|
|
|
Host.CreateDefaultBuilder(args)
|
|
|
.UseSerilog((context, config) =>
|
|
|
{
|
|
|
// 为每个实例配置独立的Serilog
|
|
|
config.WriteTo.Console(
|
|
|
outputTemplate: $"[{{Timestamp:HH:mm:ss}} {{Level:u3}}] Instance{instanceId}: {{Message:lj}}{{NewLine}}{{Exception}}")
|
|
|
.WriteTo.File(
|
|
|
path: $"./Logs/{DateTime.UtcNow:yyyy-MM-dd}/log-.txt",
|
|
|
rollingInterval: RollingInterval.Day,
|
|
|
outputTemplate: $"[{{Timestamp:yyyy-MM-dd HH:mm:ss}} {{Level:u3}}] Instance{instanceId}: {{Message:lj}}{{NewLine}}{{Exception}}");
|
|
|
})
|
|
|
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
|
|
|
.ConfigureAppConfiguration((context, config) =>
|
|
|
{
|
|
|
// 清除默认配置,从头开始构建
|
|
|
config.Sources.Clear();
|
|
|
|
|
|
// 按优先级添加配置源
|
|
|
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
|
|
.AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: true)
|
|
|
.AddJsonFile($"appsettings.instance{instanceId}.json", optional: true, reloadOnChange: true)
|
|
|
.AddEnvironmentVariables("INSTANCE_")
|
|
|
.AddCommandLine(args);
|
|
|
})
|
|
|
.ConfigureWebHostDefaults(webBuilder =>
|
|
|
{
|
|
|
webBuilder.UseStartup<Startup>();
|
|
|
|
|
|
webBuilder.ConfigureKestrel(serverOptions =>
|
|
|
{
|
|
|
Console.WriteLine(int.Parse(instanceId));
|
|
|
|
|
|
serverOptions.ListenAnyIP(1 + (int.Parse(instanceId) - 1));
|
|
|
});
|
|
|
})
|
|
|
.ConfigureServices((context, services) =>
|
|
|
{
|
|
|
services.AddSingleton(new InstanceInfo { Id = instanceId });
|
|
|
});
|
|
|
public class InstanceInfo
|
|
|
{
|
|
|
public string Id { get; set; } = "1";
|
|
|
|
|
|
}
|
|
|
private static string GetInstanceId(string[] args)
|
|
|
{
|
|
|
// 支持多种参数格式
|
|
|
foreach (var arg in args)
|
|
|
{
|
|
|
if (arg.StartsWith("--instance"))
|
|
|
{
|
|
|
if (arg == "--instance")
|
|
|
{
|
|
|
// 查找下一个参数作为实例ID
|
|
|
var index = Array.IndexOf(args, arg);
|
|
|
if (index + 1 < args.Length)
|
|
|
{
|
|
|
return args[index + 1];
|
|
|
}
|
|
|
}
|
|
|
else if (arg.StartsWith("--instance="))
|
|
|
{
|
|
|
return arg.Substring("--instance=".Length);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
// 格式: --instance1, --instance2
|
|
|
return arg.Substring("--instance".Length);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 如果没有指定实例ID,使用随机ID避免冲突
|
|
|
Random random = new Random();
|
|
|
return random.Next(0000, 9999).ToString();
|
|
|
}
|
|
|
/// <summary>
|
|
|
/// CreateHostBuilder
|
|
|
/// </summary>
|
|
|
/// <param name="args"></param>
|
|
|
/// <returns></returns>
|
|
|
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
|
|
Host.CreateDefaultBuilder(args)
|
|
|
|
|
|
.UseSerilog()
|
|
|
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
|
|
|
.ConfigureWebHostDefaults(webBuilder =>
|
|
|
{
|
|
|
webBuilder.UseStartup<Startup>();
|
|
|
});
|
|
|
|
|
|
// Exit事件
|
|
|
protected override void OnExit(ExitEventArgs e)
|
|
|
{
|
|
|
base.OnExit(e);
|
|
|
|
|
|
Log.Information($"系统退出,当前时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
|
|
|
// 释放资源
|
|
|
// ...
|
|
|
}
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|