最近做了一本地exe程序, 需要简单初始化一个.net core 10 的 Console 项目. 包括读取本地配置文件 appsettings.json,以及使用日志 啥的.
本来最开始使用 Nlog作为日志记录的 ( 之前 ZR.Admin 里面 就是用的 Nlog ) ,结果项目开发完,说需要 对接 之前一个项目的 Elasticsearch(ES) ,头大,也不太方便调试ES,所以就抄原来的项目,直接使用原来项目的配置, 改为使用Log4Net了.
控制台Console项目 ,首先肯定是要记录日志, 读取配置文件啥的.然后操作数据库,使用SqlSugar,经典的三层模式(Model,DAL,BLL)调用就行了.
这里配置文件贴一下.
1.配置文件 Log4net.config
Log4net.config连接ES日志
<?xml version="1.0" encoding="utf-8" ?>
<configuration><!-- This section contains the log4net configuration settings --><log4net><appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender"><layout type="log4net.Layout.PatternLayout" value="%date [%thread] | %-5level | %message%newline" /></appender><appender name="FileAppender" type="log4net.Appender.FileAppender"><file value="log-file.log" /><appendToFile value="true" /><layout type="log4net.Layout.PatternLayout"><conversionPattern value="%date [%thread] | %-5level| %message%newline" /></layout></appender><appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender"><file value="logfile/" /><appendToFile value="true" /><rollingStyle value="Composite" /><staticLogFileName value="false" /><datePattern value="yyyyMMdd'.log'" /><maxSizeRollBackups value="10" /><maximumFileSize value="1MB" /><layout type="log4net.Layout.PatternLayout"><conversionPattern value="%date [%thread] | %-5level | %message%newline" /></layout></appender><appender name="ElasticSearchAppender" type="log4net.ElasticSearchAppender.DotNetCore.ElasticSearchAppender, log4net.ElasticSearchAppender.DotNetCore"><Server>${"ES服务器地址:xxx.xxx.xxx.xxx"}</Server><Port>9200</Port><IndexName>${"ES服务器上搭建好的日志模块名称:xxxLog"}_%{+yyyy-MM-dd}</IndexName></appender><!-- Setup the root category, add the appenders and set the default level --><root><level value="ALL" /><appender-ref ref="ConsoleAppender" /><appender-ref ref="FileAppender" /><appender-ref ref="RollingLogFileAppender" /><!--<appender-ref ref="ElasticSearchAppender" /> --></root></log4net>
</configuration>
2.配置文件 appsettings.json
简单的任务配置以及数据库配置
{"TaskConfig": {"MaxThreadCount": 50,"ThreadSleepTime": 5, "GroupNum": 5 },"ConnectionStrings": {"conn_db_type": "3", // 数据库类型 SqlServer = 1,oracle =3,PostgreSQL=4"conn_db_main": "xxx"; // 数据库链接配置}
}
3.通用日志类 Log4NetHelper.cs
Log4NetHelper.cs 能用
using log4net;
using log4net.Config;
using log4net.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace HelpCommon
{public class Log4NetHelper{private static string repositoryName = string.Empty;private static string logName = "xxxLog";private static log4net.ILog log = log4net.LogManager.GetLogger(logName);public static void Init(){ILoggerRepository repository = LogManager.CreateRepository("xxxLog");XmlConfigurator.Configure(repository, new FileInfo("Log4net.config"));repositoryName = repository.Name;log = LogManager.GetLogger(repository.Name, logName);}public static void ConsoleInfo(string msg){Info(msg);Console.WriteLine(msg);}public static void Debug(string message){log4net.ILog log = log4net.LogManager.GetLogger(logName);if (log.IsDebugEnabled){log.Debug(message);}log = null;}public static void Debug(string message, Exception ex){if (log.IsDebugEnabled){log.Debug(message, ex);}}public static void Error(string message){if (log.IsErrorEnabled){log.Error(message);}}public static void Error(string message, Exception ex){if (log.IsErrorEnabled){log.Error(message, ex);}}public static void Fatal(string message){if (log.IsFatalEnabled){log.Fatal(message);}}public static void Fatal(string message, Exception ex){if (log.IsFatalEnabled){log.Fatal(message, ex);}}public static void Info(string message){if (log.IsInfoEnabled){log.Info(message);}}public static void Info(string message, Exception ex){if (log.IsInfoEnabled){log.Info(message, ex);}}public static void Warn(string message){if (log.IsWarnEnabled){log.Warn(message);}}public static void Warn(string message, Exception ex){if (log.IsWarnEnabled){log.Warn(message, ex);}}}
}
需要说明的是, 有时候记录日志(写文件),也要同时输出在控制台(方便观察).所以加了个 Log4NetHelper. ConsoleInfo 方法.
4.全局配置类 GlobalSetting.cs
GlobalSetting 全局配置类
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace HelpCommon
{public static class GlobalSetting{private static IConfigurationRoot config = null;private static int _dbType;public static int DbType{get{return _dbType;}}private static string _dbConnStr;public static string DbConnStr{get{return _dbConnStr;}}public static DateTime LastDbTime { get; set; }public static void Init(){var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);config = configuration.Build();// _maxCheckTime = GetSettingByInt("MaxCheckTime");// IChangeToken changeToken = config.GetReloadToken();}/// <summary>/// 初始化数据库配置/// </summary>public static void InitDB(){_dbConnStr = GetSetting("ConnectionStrings:conn_db_main");_dbType = GetSettingByInt("ConnectionStrings:conn_db_type");}/// <summary>/// 多个层级用英文:分割,例如: Logging:LogLevel:Default/// </summary>/// <param name="key"></param>/// <returns></returns>public static string GetSetting(string key){try{var obj = config[key];if (!string.IsNullOrEmpty(obj)){return obj;}return "";}catch{return "";}}/// <summary>/// 多个层级用英文:分割,例如: Logging:LogLevel:Default/// </summary>/// <param name="key"></param>/// <returns></returns>public static int GetSettingByInt(string key){var obj = config[key];if (int.TryParse(obj, out int p)){return p;}else{Console.WriteLine($"读取配置节[{key}]点错误");// 没有对应的值,返回-1return -1;}}}
}
5.程序Main方法初始化
Main方法入口 初始化日志,配置
static void Main(string[] args)
{ Log4NetHelper.Init();Log4NetHelper.ConsoleInfo("程序结束运行...");InitConfig();//这里写业务逻辑Log4NetHelper.ConsoleInfo("程序结束运行...");Console.WriteLine("程序终止运行");Console.ReadLine();
}static bool InitConfig(){try{Log4NetHelper.Info("加载配置文件并读取配置: ①数据库配置,②机器配置,③任务配置");GlobalSetting.Init();GlobalSetting.InitDB();// GlobalSetting.InitTaskConfig(); 读取配置文件参数// 检测一下数据库配置 if (GlobalSetting.DbConnStr.indexOf("xxx.xxx.xxx.xxx") > 0){Console.Write("注意:当前数据库连接为 ");Console.BackgroundColor = ConsoleColor.White;Console.ForegroundColor = ConsoleColor.Red;Console.Write(" [测试库] xxx.xxx.xxx.xxx ");Console.BackgroundColor = ConsoleColor.Black;Console.ForegroundColor = ConsoleColor.White;Console.WriteLine(" ,按回车继续...");Console.ReadLine();}Log4NetHelper.Info($"①数据库配置: 数据库类型:{GlobalSetting.DbType}");//Log4NetHelper.Info($"②机器配置:" + JsonConvert.SerializeObject(GlobalSetting.MachineConfig));//Log4NetHelper.Info($"③任务配置:" + JsonConvert.SerializeObject(GlobalSetting.TaskConfig));// 更新数据库,注册配置 (回写到数据库)//ConfigManagerBLL.SaveMachineConfig();//ConfigManagerBLL.SaveTaskConfig();// 检查数据库表里面配置的其他表或者参数, 如果没有配置, 需要提醒一下 string sjcMsf = string.Empty; ;var checkAllowRun = ConfigManagerBLL.CheckConfigStartTime(ref sjcMsf);while (!checkAllowRun){Console.WriteLine("请检查 配置表 esb_task_config,设置 主机 取数的 开始时间戳和结束时间戳.....");Thread.Sleep(5000);checkAllowRun = ConfigManagerBLL.CheckConfigStartTime(ref sjcMsf);}Log4NetHelper.ConsoleInfo(sjcMsf); return true;}catch (Exception ex){Log4NetHelper.Error("初始化读取appsettings.json配置异常", ex);return false;}
}
5.解决方案项目结构
项目结构一目了然,经典的三层结构. HelpCommon 基本都是常用的类,不过多赘述.
需要说明的是 Lib目录 ,一般是放置 第三方DLL库之类的. 这里放几个文件说明,便于了解项目.(等时间一长,很多就都忘啦)

6.分页入参,出参通用类
EsbModel 下面有2个分页的实体类,一种是泛型的(返回值),另一个是分页入参(方法传参用)
泛型分页PagedInfo
/// <summary>/// 分页参数/// </summary>public class PagedInfo<T>{/// <summary>/// 每页行数/// </summary>public int PageSize { get; set; } = 10;/// <summary>/// 当前页/// </summary>public int PageIndex { get; set; } = 1;/// <summary>/// 总记录数/// </summary>public int TotalNum { get; set; }/// <summary>/// 总页数/// </summary>public int TotalPage{get{if (TotalNum > 0){return TotalNum % this.PageSize == 0 ? TotalNum / this.PageSize : TotalNum / this.PageSize + 1;}else{return 0;}}set { }}public List<T> Result { get; set; }public Dictionary<string, object> Extra { get; set; } = new Dictionary<string, object>();public PagedInfo(){}}
分页方法入参传参 PagerInfo
public class PagerInfo
{/// <summary>/// 当前页码/// </summary>public int PageNum { get; set; }public int PageSize { get; set; }/// <summary>/// 总记录数/// </summary>public int TotalNum { get; set; }/// <summary>/// 总页码/// </summary>/// <summary>/// 总页数/// </summary>public int TotalPage{get{return TotalNum > 0 ? TotalNum % PageSize == 0 ? TotalNum / PageSize : TotalNum / PageSize + 1 : 0;}}/// <summary>/// 排序字段/// </summary>public string Sort { get; set; } = string.Empty;/// <summary>/// 排序类型,前端传入的是"ascending","descending"/// </summary>public string SortType { get; set; } = string.Empty;public PagerInfo(){PageNum = 1;PageSize = 20;}public PagerInfo(int page = 1, int pageSize = 20){PageNum = page;PageSize = pageSize;}
}
7. 数据库操作 SqlSugarHelper
SqlSugarHelper 数据库操作
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
using System.Collections;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data;namespace HelpCommon
{public static class SqlSugarHelper{public static string _connStr;public static string connStr{get{if (string.IsNullOrEmpty(_connStr)){_connStr = GlobalSetting.DbConnStr;}return _connStr;}}public static SqlSugarScope _db = null;public static SqlSugarScope db{get{if (_db == null){_db = new SqlSugarScope(new SqlSugar.ConnectionConfig(){ConnectionString = connStr,DbType = SqlSugar.DbType.Oracle,IsAutoCloseConnection = true,// 需要查看运行时的sql,打开下面的注释//AopEvents = new AopEvents//{// OnLogExecuting = (sql, p) =>// {// Parallel.For(0, 1, e =>// {// string sqlStr = GetParas(p) + "【SQL语句】:" + sql;// Console.ForegroundColor = ConsoleColor.Green;// Console.WriteLine(sqlStr);// Console.ForegroundColor = ConsoleColor.White;// });// }//},}); ;}return _db;}}private static string GetParas(SugarParameter[] pars){string key = "【SQL参数】:";foreach (var param in pars){key += $"{param.ParameterName}:{param.Value}\n";}return key;}/*批量新增/修改 使用: db.Storageable<T>(List<T>list).ExecuteCommand();sql->List<T> 使用: db.Ado.SqlQuery<T>(sql, parms);*/public static DataTable GetDataTable(string sql, object parms = null){return db.Ado.GetDataTable(sql, parms);}public static int ExecuteNonQuery(string sql, object parms = null){return db.Ado.ExecuteCommand(sql, parms);}public static object GetScalar(string sql, object parms = null){return db.Ado.GetScalar(sql, parms);}public static DateTime GetDbTime(){return Convert.ToDateTime(db.Ado.GetScalar("select sysdate from dual"));}public static DateTime GetDbTimeStemp(){var obj = db.Ado.GetScalar("select to_char(SYSTIMESTAMP,'YYYY-MM-DD HH24:MI:SS.ff6') from dual");return TimeHelper.StrToSjc(obj.ToString());}}
}
需要说明的是 批量保存 和 实体类查询 方法
批量新增/修改 使用: db.Storageable<T>(List<T>list).ExecuteCommand();
sql -> List<T> 使用: db.Ado.SqlQuery<T>(sql, parms);