wpf项目中使用host background service
App.xaml.cs
using System;
using System.Windows;
using SecsDemo.Application.DependencyInjection;
using SecsDemo.Automation.ViewModels;
using SecsDemo.Automation.Views;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging;
namespace SecsDemo.Automation;
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : System.Windows.Application
{
public IHost AppHost { get; private set; } = ConfigureServices();
/// <summary>
/// Gets the current <see cref="App"/> instance in use
/// </summary>
public static new App Current => (App)System.Windows.Application.Current;
/// <summary>
/// Application Entry for SecsDemoCoc
/// </summary>
public App()
{
}
private static IHost ConfigureServices()
{
// 使用 HostApplicationBuilder 创建主机,整合依赖注入和服务配置
HostApplicationBuilder hostApplicationBuilder = Host.CreateApplicationBuilder();
hostApplicationBuilder.Configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
hostApplicationBuilder.Services.AddSecsGemServices(hostApplicationBuilder.Configuration);
hostApplicationBuilder.Services.AddLogging(loggingBuilder =>
{
loggingBuilder.ClearProviders();
loggingBuilder.SetMinimumLevel(LogLevel.Debug);
loggingBuilder.AddNLog(hostApplicationBuilder.Configuration);
});
hostApplicationBuilder.Services.AddTransient<MainViewModel>();
hostApplicationBuilder.Services.AddTransient<MainView>(sp => new MainView { DataContext = sp.GetService<MainViewModel>() });
return hostApplicationBuilder.Build();
}
private void Application_Startup(object sender, StartupEventArgs e)
{
AppHost.Start();
var mainViewModel = new MainView { DataContext = Activator.CreateInstance<MainViewModel>() };
var mainWindow = AppHost.Services.GetRequiredService<MainView>();
mainWindow.DataContext = mainViewModel;
mainWindow.Show();
}
}
App.xaml
<Application x:Class="SecsDemo.Automation.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="Application_Startup">
<Application.Resources />
</Application>
SecsGemServiceExtensions.cs
using System.Reflection;
using SecsDemo.Application.SecsHandler;
using SecsDemo.Application.SecsManager;
using SecsDemo.Application.SecsSender;
using SecsDemo.Application.Services;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging;
using Secs4Net;
namespace SecsDemo.Application.DependencyInjection;
public static class SecsGemServiceExtensions
{
public static void AddSecsGemServices(this IServiceCollection collection, IConfigurationRoot configurationRoot)
{
// 添加SECS服务
Console.WriteLine(configurationRoot.GetSection("Secs4net"));
collection.Configure<SecsGemOptions>(configurationRoot.GetSection("Secs4net"));
collection.AddSingleton<ISecsConnection, HsmsConnection>();
collection.AddSingleton<ISecsGem, SecsGem>();
collection.AddSingleton<ISecsGemLogger, DeviceLogger>();
collection.AddHostedService<SecsBackgroundService>();
collection.AddTransient<ISecsMessageHandler, SecsMessageHandler>();
}
}
SecsBackgroundService.cs
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Secs4Net;
namespace SecsDemo.Application.Services;
public class SecsBackgroundService : BackgroundService
{
private readonly ILogger<SecsBackgroundService> _logger;
private readonly ISecsConnection _secsConnection;
private readonly ISecsGem _secsGem;
private readonly IEnumerable<ISecsMessageHandler> _messageHandlers;
public SecsBackgroundService(ILogger<SecsBackgroundService> logger, ISecsConnection secsConnection, ISecsGem secsGem, IEnumerable<ISecsMessageHandler> messageHandlers)
{
_logger = logger;
_secsConnection = secsConnection;
_secsGem = secsGem;
_messageHandlers = messageHandlers;
_logger.LogInformation("SecsBackgroundService constructor called.");
_logger.LogInformation($"SecsConnection: {_secsConnection.GetType().FullName}");
_logger.LogInformation($"SecsGem: {_secsGem.GetType().FullName}");
_secsConnection.ConnectionChanged += (sender, state) =>
{
_logger.LogInformation($"SECS connection state changed to: {state}");
};
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
_logger.LogInformation("Starting SECS background service...");
_secsConnection.Start(stoppingToken);
_logger.LogInformation("SECS connection started.");
await foreach (var primaryMessage in _secsGem.GetPrimaryMessageAsync(stoppingToken))
{
using var msg = primaryMessage.PrimaryMessage;
_logger.LogInformation($"Received SECS message: {msg}");
// 处理接收到的消息
// await HandlePrimaryMessage(msg);
// 分发消息到所有注册的消息处理器
foreach (var handler in _messageHandlers)
{
await handler.HandleMessageAsync(msg);
}
// 回复从消息
using var secondaryMsg = CreateSecondaryMessage(msg);
await primaryMessage.TryReplyAsync(secondaryMsg, stoppingToken);
}
}
catch (OperationCanceledException)
{
_logger.LogInformation("SECS background service is being cancelled.");
}
catch (Exception ex)
{
_logger.LogError(ex, "An error occurred in the SECS background service.");
}
}
private async Task HandlePrimaryMessage(SecsMessage primaryMessage)
{
// 这里可以根据具体业务逻辑处理主消息
_logger.LogInformation($"Processing SECS message: {primaryMessage}");
}
private SecsMessage CreateSecondaryMessage(SecsMessage primaryMessage)
{
// 创建从消息,根据主消息的流和功能号创建
return new SecsMessage(primaryMessage.S, (byte)(primaryMessage.F + 1)) { SecsItem = primaryMessage.SecsItem };
}
}
SecsMessageHandler.cs
using Microsoft.Extensions.Logging;
using Secs4Net;
namespace SecsDemo.Application.Services;
public class SecsMessageHandler : ISecsMessageHandler
{
private readonly ILogger<SecsMessageHandler> _logger;
public SecsMessageHandler(ILogger<SecsMessageHandler> logger)
{
_logger = logger;
}
public async Task HandleMessageAsync(SecsMessage message)
{
_logger.LogInformation($"Handling SECS message: {message}");
// 在这里添加具体的消息处理逻辑
await Task.CompletedTask;
}
}
ISecsMessageHandler.cs
using Secs4Net;
namespace SecsDemo.Application.Services;
public interface ISecsMessageHandler
{
Task HandleMessageAsync(SecsMessage message);
}