[C#]Nlog寫進DB的ConnectionStringName改成用程式碼來指定

因為在Nlog裡面是用XML來指定web.config的connection string,但是為了加密要從程式面解密,所以必須要先解密再指定,如何實做呢?

前言

不管是在Nlog的技術文件,或者相關文章,很少看到Nlog的ConnectionString改成從程式碼來切換,所以就自我記錄一下。

Nlog寫進DB的XML文件參考

先看一下原本的做法是直接寫在Nlog.config

 <target name="db" xsi:type="Database"
            connectionStringName="LogConnectionString"
            commandText="INSERT INTO LOG_ERROR(ERROR_THREAD_ID, ERROR_MACHINE_NAME, ERROR_NAME, ERROR_LEVEL, ERROR_MESSAGE, ERROR_CALL_SITE, ERROR_EXCEPTION, ERROR_STACK_TRACE) 
            VALUES (@ThreadId, @MachineName, @LogName, @LogLevel, @LogMessage, @CallSite, @Exception, @Stacktrace)">
      <parameter name="@ThreadId" layout="${threadid}"/>
      <parameter name="@MachineName" layout="${machinename}"/>
      <parameter name="@LogName" layout="${logger}"/>
      <parameter name="@LogLevel" layout="${level}"/>
      <parameter name="@LogMessage" layout="${message}"/>
      <parameter name="@CallSite" layout="${callsite:filename=true}"/>
      <parameter name="@Exception" layout="${exception}"/>
      <parameter name="@Stacktrace" layout="${stacktrace}"/>
    </target>

如果我要從程式碼指定的話,我就先把ConnectionStringName給移除掉,改成如下。

 <target name="db" xsi:type="Database"
            commandText="INSERT INTO LOG_ERROR(ERROR_THREAD_ID, ERROR_MACHINE_NAME, ERROR_NAME, ERROR_LEVEL, ERROR_MESSAGE, ERROR_CALL_SITE, ERROR_EXCEPTION, ERROR_STACK_TRACE) 
            VALUES (@ThreadId, @MachineName, @LogName, @LogLevel, @LogMessage, @CallSite, @Exception, @Stacktrace)">
      <parameter name="@ThreadId" layout="${threadid}"/>
      <parameter name="@MachineName" layout="${machinename}"/>
      <parameter name="@LogName" layout="${logger}"/>
      <parameter name="@LogLevel" layout="${level}"/>
      <parameter name="@LogMessage" layout="${message}"/>
      <parameter name="@CallSite" layout="${callsite:filename=true}"/>
      <parameter name="@Exception" layout="${exception}"/>
      <parameter name="@Stacktrace" layout="${stacktrace}"/>
    </target>

C#部份

只要在記錄log之前先指定了db的部份就行了,範例如下

 DatabaseTarget databaseTarget = null;
            Target targetWrapper = LogManager.Configuration.FindTargetByName("db");
            if (targetWrapper is AsyncTargetWrapper)
            {
                databaseTarget = (targetWrapper as AsyncTargetWrapper).WrappedTarget as DatabaseTarget;
            }
            else if (targetWrapper is DatabaseTarget)
            {
                databaseTarget = targetWrapper as DatabaseTarget;
            }

            if (databaseTarget != null)
            {
                databaseTarget.ConnectionString = WebConfigurationManager.ConnectionStrings["LogConnectionString"].ConnectionString;
                LogManager.ReconfigExistingLoggers();
            }

比較完整的程式碼可能如下,這只是筆者拿實際程式碼來改寫。

[RoutePrefix("Employee")]
    public class EmployeeController : ApiController
    {
        private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

        [Route("editProfile")]
        public async Task<IHttpActionResult> PostEditUserProfile(UspEmployeeUpdateDto param)
        {
            try
            {
                //請忽略下面此行,這只是筆者現實專案中的某個方法,還有傳入參數
                await service.EmployeeService.UpdateEmployeeRegisterData(param);
                return Ok();
            }
            catch (Exception ex)
            {
                DatabaseTarget databaseTarget = null;
                Target targetWrapper = LogManager.Configuration.FindTargetByName("db");
                if (targetWrapper is AsyncTargetWrapper)
                {
                    databaseTarget = (targetWrapper as AsyncTargetWrapper).WrappedTarget as DatabaseTarget;
                }
                else if (targetWrapper is DatabaseTarget)
                {
                    databaseTarget = targetWrapper as DatabaseTarget;
                }

                if (databaseTarget != null)
                {
                    databaseTarget.ConnectionString = WebConfigurationManager.ConnectionStrings["LogConnectionString"].ConnectionString;
                    LogManager.ReconfigExistingLoggers();
                }
                logger.Fatal(ex);
                throw;
            }
           
        }
    }

結論

當然實際過程都需要再包裝一下,比如指定db的地方,不可能要到處複製貼上,再請各位自行去封裝,如有更好做法或意見,再請多多指導。