因為在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的地方,不可能要到處複製貼上,再請各位自行去封裝,如有更好做法或意見,再請多多指導。