将NlogHelper,和NotificationHelper,改为服务的方式注入使用
This commit is contained in:
@@ -59,10 +59,10 @@ public partial class DataServices : ObservableObject
|
||||
|
||||
/// <summary>
|
||||
/// DataServices类的构造函数。
|
||||
/// 注入ILogger<DataServices>,并初始化各个数据仓库。
|
||||
/// 初始化各个数据仓库。
|
||||
/// </summary>
|
||||
/// <param name="mapper">AutoMapper 实例。</param>
|
||||
/// <param name="varDataRepository"></param>
|
||||
/// <param name="dataCenterService">数据服务中心实例。</param>
|
||||
public DataServices(IMapper mapper, IDataCenterService dataCenterService)
|
||||
{
|
||||
_mapper = mapper;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// 文件: DMS.WPF/Services/NavigationService.cs
|
||||
|
||||
using DMS.Helper;
|
||||
using DMS.ViewModels;
|
||||
using DMS.WPF.ViewModels;
|
||||
using DMS.WPF.ViewModels.Items;
|
||||
@@ -11,6 +10,7 @@ using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using DMS.WPF.Interfaces;
|
||||
using DMS.WPF.Services;
|
||||
|
||||
namespace DMS.WPF.Services;
|
||||
|
||||
@@ -43,8 +43,8 @@ public class NavigationService : INavigationService
|
||||
var viewModel = GetViewModelByKey(menu.TargetViewKey);
|
||||
if (viewModel == null)
|
||||
{
|
||||
|
||||
NotificationHelper.ShowError($"切换界面失败,没有找到界面:{menu.TargetViewKey}");
|
||||
var notificationService = App.Current.Services.GetRequiredService<NotificationService>();
|
||||
notificationService.ShowError($"切换界面失败,没有找到界面:{menu.TargetViewKey}");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
191
DMS.WPF/Services/NotificationService.cs
Normal file
191
DMS.WPF/Services/NotificationService.cs
Normal file
@@ -0,0 +1,191 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using DMS.Core.Enums;
|
||||
using DMS.Message;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace DMS.WPF.Services;
|
||||
|
||||
/// <summary>
|
||||
/// 通知服务类,用于显示各种类型的通知消息,并集成日志记录功能。
|
||||
/// 新增了通知节流功能,以防止在短时间内向用户发送大量重复的通知。
|
||||
/// </summary>
|
||||
public class NotificationService
|
||||
{
|
||||
private readonly ILogger<NotificationService> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// 内部类,用于存储节流通知的状态信息。
|
||||
/// </summary>
|
||||
private class ThrottledNotificationInfo
|
||||
{
|
||||
public int Count;
|
||||
public Timer Timer;
|
||||
public NotificationType NotificationType;
|
||||
}
|
||||
|
||||
private readonly ConcurrentDictionary<string, ThrottledNotificationInfo> _throttledNotifications = new ConcurrentDictionary<string, ThrottledNotificationInfo>();
|
||||
private const int ThrottleTimeSeconds = 30;
|
||||
|
||||
public NotificationService(ILogger<NotificationService> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 内部核心通知发送方法,包含了节流逻辑。
|
||||
/// </summary>
|
||||
private void SendNotificationInternal(string msg, NotificationType notificationType, bool throttle, Exception exception, string callerFilePath, string callerMember, int callerLineNumber)
|
||||
{
|
||||
// 根据通知类型决定日志级别,并使用 ILogger 记录日志
|
||||
if (notificationType == NotificationType.Error)
|
||||
{
|
||||
_logger.LogError(exception, $"[{callerFilePath}:{callerMember}:{callerLineNumber}] {msg}");
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (notificationType)
|
||||
{
|
||||
case NotificationType.Info:
|
||||
_logger.LogInformation($"[{callerFilePath}:{callerMember}:{callerLineNumber}] {msg}");
|
||||
break;
|
||||
case NotificationType.Success:
|
||||
_logger.LogInformation($"[{callerFilePath}:{callerMember}:{callerLineNumber}] {msg}");
|
||||
break;
|
||||
case NotificationType.Warning:
|
||||
_logger.LogWarning($"[{callerFilePath}:{callerMember}:{callerLineNumber}] {msg}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果不启用通知节流,则直接发送通知并返回。
|
||||
if (!throttle)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send(new NotificationMessage(msg, notificationType));
|
||||
return;
|
||||
}
|
||||
|
||||
var key = $"{callerFilePath}:{callerLineNumber}:{msg}";
|
||||
|
||||
_throttledNotifications.AddOrUpdate(
|
||||
key,
|
||||
// --- 添加逻辑:当通知第一次被节流时执行 ---
|
||||
_ =>
|
||||
{
|
||||
// 1. 首次出现,立即发送一次通知。
|
||||
WeakReferenceMessenger.Default.Send(new NotificationMessage(msg, notificationType));
|
||||
|
||||
// 2. 创建新的节流信息对象。
|
||||
var newThrottledNotification = new ThrottledNotificationInfo
|
||||
{
|
||||
Count = 1,
|
||||
NotificationType = notificationType
|
||||
};
|
||||
|
||||
// 3. 创建并启动计时器。
|
||||
newThrottledNotification.Timer = new Timer(s =>
|
||||
{
|
||||
if (_throttledNotifications.TryRemove(key, out var finishedNotification))
|
||||
{
|
||||
finishedNotification.Timer.Dispose();
|
||||
if (finishedNotification.Count > 1)
|
||||
{
|
||||
var summaryMsg = $"消息 '{msg}' 在过去 {ThrottleTimeSeconds} 秒内出现了 {finishedNotification.Count} 次。";
|
||||
WeakReferenceMessenger.Default.Send(new NotificationMessage(summaryMsg, finishedNotification.NotificationType));
|
||||
}
|
||||
}
|
||||
}, null, ThrottleTimeSeconds * 1000, Timeout.Infinite);
|
||||
|
||||
return newThrottledNotification;
|
||||
},
|
||||
// --- 更新逻辑:当通知在节流窗口内再次出现时执行 ---
|
||||
(_, existingNotification) =>
|
||||
{
|
||||
Interlocked.Increment(ref existingNotification.Count);
|
||||
return existingNotification;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示一个通用通知消息,并根据通知类型记录日志。支持节流。
|
||||
/// </summary>
|
||||
/// <param name="msg">通知消息内容。</param>
|
||||
/// <param name="notificationType">通知类型(如信息、错误、成功等)。</param>
|
||||
/// <param name="throttle">是否启用通知节流。</param>
|
||||
/// <param name="callerFilePath">自动捕获:调用此方法的源文件完整路径。</param>
|
||||
/// <param name="callerLineNumber">自动捕获:调用此方法的行号。</param>
|
||||
public void ShowMessage(string msg, NotificationType notificationType = NotificationType.Info, bool throttle = true,
|
||||
[CallerFilePath] string callerFilePath = "",
|
||||
[CallerLineNumber] int callerLineNumber = 0)
|
||||
{
|
||||
SendNotificationInternal(msg, notificationType, throttle, null, callerFilePath, "", callerLineNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示一个错误通知消息,并记录错误日志。支持节流。
|
||||
/// </summary>
|
||||
/// <param name="msg">错误消息内容。</param>
|
||||
/// <param name="exception">可选:要记录的异常对象。</param>
|
||||
/// <param name="throttle">是否启用通知和日志节流。</param>
|
||||
/// <param name="callerFilePath">自动捕获:调用此方法的源文件完整路径。</param>
|
||||
/// <param name="callerMember">自动捕获:调用此方法的成员或属性名称。</param>
|
||||
/// <param name="callerLineNumber">自动捕获:调用此方法的行号。</param>
|
||||
public void ShowError(string msg, Exception exception = null, bool throttle = true,
|
||||
[CallerFilePath] string callerFilePath = "",
|
||||
[CallerMemberName] string callerMember = "",
|
||||
[CallerLineNumber] int callerLineNumber = 0)
|
||||
{
|
||||
SendNotificationInternal(msg, NotificationType.Error, throttle, exception, callerFilePath, callerMember, callerLineNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示一个成功通知消息,并记录信息日志。支持节流。
|
||||
/// </summary>
|
||||
/// <param name="msg">成功消息内容。</param>
|
||||
/// <param name="throttle">是否启用通知和日志节流。</param>
|
||||
/// <param name="callerFilePath">自动捕获:调用此方法的源文件完整路径。</param>
|
||||
/// <param name="callerMember">自动捕获:调用此方法的成员或属性名称。</param>
|
||||
/// <param name="callerLineNumber">自动捕获:调用此方法的行号。</param>
|
||||
public void ShowSuccess(string msg, bool throttle = true,
|
||||
[CallerFilePath] string callerFilePath = "",
|
||||
[CallerMemberName] string callerMember = "",
|
||||
[CallerLineNumber] int callerLineNumber = 0)
|
||||
{
|
||||
SendNotificationInternal(msg, NotificationType.Success, throttle, null, callerFilePath, callerMember, callerLineNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示一个信息通知消息,并记录信息日志。支持节流。
|
||||
/// </summary>
|
||||
/// <param name="msg">信息消息内容。</param>
|
||||
/// <param name="throttle">是否启用通知和日志节流。</param>
|
||||
/// <param name="callerFilePath">自动捕获:调用此方法的源文件完整路径。</param>
|
||||
/// <param name="callerMember">自动捕获:调用此方法的成员或属性名称。</param>
|
||||
/// <param name="callerLineNumber">自动捕获:调用此方法的行号。</param>
|
||||
public void ShowInfo(string msg, bool throttle = true,
|
||||
[CallerFilePath] string callerFilePath = "",
|
||||
[CallerMemberName] string callerMember = "",
|
||||
[CallerLineNumber] int callerLineNumber = 0)
|
||||
{
|
||||
SendNotificationInternal(msg, NotificationType.Info, throttle, null, callerFilePath, callerMember, callerLineNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示一个警告通知消息,并记录警告日志。支持节流。
|
||||
/// </summary>
|
||||
/// <param name="msg">警告消息内容。</param>
|
||||
/// <param name="throttle">是否启用通知和日志节流。</param>
|
||||
/// <param name="callerFilePath">自动捕获:调用此方法的源文件完整路径。</param>
|
||||
/// <param name="callerMember">自动捕获:调用此方法的成员或属性名称。</param>
|
||||
/// <param name="callerLineNumber">自动捕获:调用此方法的行号。</param>
|
||||
public void ShowWarn(string msg, bool throttle = true,
|
||||
[CallerFilePath] string callerFilePath = "",
|
||||
[CallerMemberName] string callerMember = "",
|
||||
[CallerLineNumber] int callerLineNumber = 0)
|
||||
{
|
||||
SendNotificationInternal(msg, NotificationType.Warning, throttle, null, callerFilePath, callerMember, callerLineNumber);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user