You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免重复编写ILogger消息并实现消息复用?

避免日志与通知重复构建消息的方案

要解决重复编写消息模板和参数的问题,同时保留结构化日志的优势(即日志系统能识别占位符对应的参数,而非仅记录拼接后的字符串),可以用以下几种实用方案:

1. 封装通用通知服务

创建一个统一的服务类,整合日志记录和弹窗通知逻辑,只需传入一次模板和参数即可完成多渠道推送:

public class NotificationService
{
    private readonly ILogger<NotificationService> _logger;

    public NotificationService(ILogger<NotificationService> logger)
    {
        _logger = logger;
    }

    // 通用方法:记录结构化日志 + 显示成功弹窗
    public async Task LogAndShowSuccessAlert(string messageTemplate, params object[] args)
    {
        // 保留结构化日志特性:直接传入模板和参数
        _logger.LogInformation(messageTemplate, args);
        
        // 渲染成用户可见的字符串(复用模板和参数)
        var userFriendlyMessage = string.Format(messageTemplate, args);
        await App.Show.AlertSuccess(userFriendlyMessage);
    }

    // 可扩展:添加其他类型的通知(如错误弹窗、进度报告等)
    public async Task LogAndShowErrorAlert(string messageTemplate, params object[] args)
    {
        _logger.LogError(messageTemplate, args);
        var userFriendlyMessage = string.Format(messageTemplate, args);
        await App.Show.AlertError(userFriendlyMessage);
    }
}

使用方式:

// 注入NotificationService后调用
var productContracts = await context.ProductContracts.ToListAsync();
var contractListSummary = productContracts.ValuesToStringNewLines(c => c.GetDescription());

await _notificationService.LogAndShowSuccessAlert(
    "All contracts are up to date:\r\n{ContractListSummary}",
    contractListSummary
);

优势:集中管理所有通知逻辑,后续扩展新渠道(如邮件、进度条)只需在服务中添加方法,代码复用性最高。

2. 扩展Logger的链式方法

通过扩展方法实现类似你想要的链式调用风格,同时保留结构化日志:

public static class LoggerNotificationExtensions
{
    // 扩展ILogger,添加日志+弹窗的链式方法
    public static async Task ThenShowSuccessAlert(this ILogger logger, string messageTemplate, params object[] args)
    {
        logger.LogInformation(messageTemplate, args);
        var userMessage = string.Format(messageTemplate, args);
        await App.Show.AlertSuccess(userMessage);
    }

    // 若想先执行日志再自定义后续操作,可返回包含模板和参数的对象
    public static LoggedMessage LogInfoWithPayload(this ILogger logger, string messageTemplate, params object[] args)
    {
        logger.LogInformation(messageTemplate, args);
        return new LoggedMessage(messageTemplate, args);
    }
}

// 用于承载日志模板和参数的结构体
public struct LoggedMessage
{
    public string Template { get; }
    public object[] Args { get; }

    public LoggedMessage(string template, object[] args)
    {
        Template = template;
        Args = args;
    }

    public async Task ShowSuccessAlert()
    {
        var message = string.Format(Template, Args);
        await App.Show.AlertSuccess(message);
    }

    // 可扩展其他通知方法
    public async Task ShowProgressReport()
    {
        var message = string.Format(Template, Args);
        await App.Show.UpdateProgress(message);
    }
}

使用方式:

// 直接链式调用
await logger.ThenShowSuccessAlert(
    "All contracts are up to date:\r\n{ContractListSummary}",
    contractListSummary
);

// 或先记录日志,再灵活选择后续操作
logger.LogInfoWithPayload(
    "All contracts are up to date:\r\n{ContractListSummary}",
    contractListSummary
).ShowSuccessAlert();

优势:写法简洁直观,符合你期望的链式调用习惯,无需额外注入服务。

3. 复用消息模板常量

如果只是想避免重复写相同的模板字符串,可以把常用模板定义为常量:

public static class MessageTemplates
{
    public const string ContractsUpToDate = "All contracts are up to date:\r\n{ContractListSummary}";
    public const string DataSavedSuccess = "Data {EntityName} saved successfully (ID: {EntityId})";
}

使用方式:

var contractListSummary = productContracts.ValuesToStringNewLines(c => c.GetDescription());

// 日志和弹窗复用同一个模板
logger.LogInformation(MessageTemplates.ContractsUpToDate, contractListSummary);
await App.Show.AlertSuccess(string.Format(MessageTemplates.ContractsUpToDate, contractListSummary));

优势:改动最小,适合模板数量不多的场景,避免拼写错误。

关键注意点

不要直接使用拼接后的字符串(如$"All contracts...")同时传给日志和弹窗,因为这样会丢失结构化日志的核心价值:日志系统无法识别占位符对应的参数,只能记录完整字符串,后续无法通过参数值搜索、过滤日志。

内容的提问来源于stack exchange,提问作者Sean

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 21:46:08