DNN搜索模块无匹配搜索词日志开发及相关技术咨询
Great question—let's break this down into practical, DNN-aligned solutions that balance best practices with your specific needs:
First, let's settle the logging method debate:
- Prioritize DNN's built-in Log4Net: It's already integrated into the platform, so you get out-of-the-box benefits like configurable rolling logs, automatic archiving, log level filtering, and alignment with DNN's existing logging ecosystem. No need to reinvent the wheel for file management or error handling.
- Direct TXT files only if you have extreme simplicity needs: While writing directly to a TXT is trivial, you lose all Log4Net's safeguards (like permission handling, log rotation, and centralized configuration). It's not recommended for production unless you're dealing with a one-off, low-volume use case.
DNN has standardized directory structures that avoid permission issues and align with platform conventions. Always use DNN's API to resolve paths instead of hardcoding:
- Global cross-portal logs: Use the default portal's Logs folder to store logs that apply to all portals on your instance:
var logPath = Path.Combine(Globals.ApplicationMapPath, "Portals", "_default", "Logs", "NoMatchSearches.log"); - Portal-specific logs: If you need separate logs per portal, target the portal's individual Logs directory:
var logPath = Path.Combine(Globals.ApplicationMapPath, "Portals", PortalSettings.Current.PortalId.ToString(), "Logs", "NoMatchSearches.log");
Important: Ensure the
Logsdirectory hasModifypermissions for your DNN application pool account—DNN usually configures this by default, but double-check if you're creating a new subfolder.
Let's build a fully reusable solution using DNN's native tools:
1. Logging No-Match Search Terms with DNN's ILogger
DNN wraps Log4Net in a LoggerSource API that's easy to use. Here's how to log missing search results with context:
using DotNetNuke.Services.Logging; // Inside your search module's code after detecting no matches var sanitizedSearchTerm = HttpUtility.HtmlEncode(searchTerm); // Sanitize to avoid injection/format issues var logger = LoggerSource.Instance.GetLogger(typeof(YourSearchModuleClass)); // Log with useful context: timestamp, portal ID, user ID (if logged in) logger.Warn($"No search results found | Portal ID: {PortalSettings.Current.PortalId} | User ID: {UserInfo.UserID} | Search Term: {sanitizedSearchTerm}");
To isolate these logs into their own file, add a custom appender to your log4net.config:
<appender name="NoMatchSearchAppender" type="log4net.Appender.RollingFileAppender"> <file value="Portals/_default/Logs/NoMatchSearches.log" /> <appendToFile value="true" /> <rollingStyle value="Date" /> <datePattern value="yyyyMMdd" /> <maxSizeRollBackups value="30" /> <!-- Keep 30 days of logs --> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%level] %message%newline" /> </layout> </appender> <!-- Route logs from your module to this appender --> <logger name="YourModuleNamespace.YourSearchModuleClass" additivity="false"> <level value="WARN" /> <appender-ref ref="NoMatchSearchAppender" /> </logger>
2. Automate Sending Logs to Admins with DNN Scheduler
DNN's Task Scheduler is perfect for recurring tasks like sending logs. Here's how to build a custom scheduler task:
- Create a scheduler class that inherits from
SchedulerClientBase:
using DotNetNuke.Services.Scheduling; using DotNetNuke.Services.Mail; using System.IO; public class SendNoMatchSearchLogs : SchedulerClientBase { public SendNoMatchSearchLogs(ScheduleHistoryItem objScheduleHistoryItem) : base(objScheduleHistoryItem) { } public override void DoWork() { try { // Get log path (adjust to portal-specific path if needed) var logPath = Path.Combine(Globals.ApplicationMapPath, "Portals", "_default", "Logs", "NoMatchSearches.log"); if (!File.Exists(logPath)) { ScheduleHistoryItem.Succeeded = true; ScheduleHistoryItem.AddLogNote("No log file found to send."); return; } // Read and send log content var logContent = File.ReadAllText(logPath); var adminEmail = HostSettings.Instance.AdminEmail; var subject = $"No-Match Search Logs - {DateTime.Now:yyyy-MM-dd}"; // Use DNN's built-in mail service to avoid SMTP configuration issues Mail.SendMail(adminEmail, adminEmail, "", subject, logContent, "", "", "", "", "", true); // Optional: Archive the log after sending to avoid resending old data var archivePath = Path.Combine(Path.GetDirectoryName(logPath), $"NoMatchSearches_{DateTime.Now:yyyyMMdd}.log"); File.Move(logPath, archivePath); ScheduleHistoryItem.Succeeded = true; ScheduleHistoryItem.AddLogNote("Successfully sent no-match search logs to admin."); } catch (Exception ex) { ScheduleHistoryItem.Succeeded = false; ScheduleHistoryItem.AddLogNote($"Error sending logs: {ex.Message}"); Errored(ref ex); } } }
- Register the task in DNN:
- Go to Host > Scheduler > Add New Schedule
- Fill in the task name, set the type to your full class name (e.g.,
YourModuleNamespace.SendNoMatchSearchLogs), choose a frequency (e.g., daily at 2 AM), and save.
If you plan to analyze search terms later, storing them in a custom DNN database table might be more flexible:
- Use DNN's Table Creator tool (under Host > SQL) to create a table with columns like
SearchTerm,CreatedDate,PortalId,UserId. - Modify your module to insert records instead of writing logs.
- Adjust the scheduler task to query the table, generate a summary, and send it to admins (instead of sending raw log files).
内容的提问来源于stack exchange,提问作者Tig7r

