[Elmah] 保護 Elmah 的連線字串

從大神 Kevin 那邊知道 Arebis.Web.Mvc.ElmahDashboard 這個 Dash Board套件,它比 Elmah.axd 更加的友善,使用後讓 Log Viewer、Search 的友善度提升,二話不說立馬納入專案內;有在使用 Elmah + Sql Server 的夥伴,可以試著使用看看
http://getglimpse.com/
http://kevintsengtw.blogspot.tw/2016/05/aspnet-mvc-elmah-dashboard-elmah-sql.html

這裡將分享保護 Elmah Connect String 的使用經驗,不會提到安裝套件步驟

我的專案是 WebForm + EF + Elmah + NLog To Elmah + Arebis.Web.Mvc.ElmahDashboard,若動到了保護 Elmah 的連線字串,會影響到 Elmah、Arebis.Web.Mvc.ElmahDashboard 和 NLog To Elmah,你應該適實際調整修改影響範圍

開發環境

  • Windows 10 Enterprise x64 CHT
  • VS2015 Update3
  • Entity Framework 6.1.3
  • Elmah 1.22
  • NLog 4.3.4
  • Arebis.Web.Mvc.ElmahDashboard 1.0.0
  • Glimpse 1.8.6

解密

這裡會用到我自行開發連線字串的解密、連線工廠,不影響主要思路,就不公布惹,實際做法可參考

連線字串的加解密方式可參考黑大的文章
http://blog.darkthread.net/post-2015-11-28-encrypt-ef-connstring.aspx

連線工廠可參考以下連結:
https://github.com/codetuner/Arebis.Web.Mvc.ElmahDashboard/blob/master/ElmahDashboardHostingApp/Areas/MvcElmahDashboard/Code/ElmahDashboardContext.cs
http://getglimpse.com/Docs/Manual-ADO-Integration

開始實作

@Web.Config

我加密後的連線字串如下圖:

 

原本在 Web.Config 裡面設定的設定已經用不到了 我把它挪到 Application_Start

 

@Global.asax.cs

Elmah.ServiceCenter.Current 的型別是 ServiceProviderQueryHandler 委派,這裡我用 Lambda 的寫法

我要在 Lambda 裡解密連線字串並重新裝載 SqlErrorLog

ConnectionFactory.GetConnectionString 是我自己的解密方法

private static volatile ServiceContainer s_elmahServiceContainer;
private static readonly object s_lockElmahServiceContainer = new object();
protected void Application_Start(object sender, EventArgs e)
{

	var parent = ServiceCenter.Current;
	ServiceCenter.Current = context =>
							{
								lock (s_lockElmahServiceContainer)
								{
									if (s_elmahServiceContainer != null)
									{
										return s_elmahServiceContainer;
									}

									s_elmahServiceContainer = new ServiceContainer(parent(context));
									//decrypt connection string
									var connectionString =
										ConnectionFactory.GetConnectionString("Elmah");
									var log = new SqlErrorLog(connectionString);

									log.ApplicationName = AppSetting.APPLICATION_NAME;
									s_elmahServiceContainer.AddService(typeof(ErrorLog), log);


									return s_elmahServiceContainer;
								}
							};
}
log.ApplicationName 對 Dashboard 來講很重要,千萬別漏掉它

 

@ElmahDashboardContext.cs

Arebis.Web.Mvc.ElmahDashboard 有自己的連線物件,也必須要解密連線字串

ConnectionString.Decrypt 是我自己的解密方法

private static DbConnection CreateConnection(DbProviderFactory dbProviderFactory, string connectionString)
{
	var conn = dbProviderFactory.CreateConnection();

	if (connectionString.Contains(Utility.PROTECT_TEXT))
	{
		connectionString = ConnectionString.Decrypt(connectionString);
	}
	conn.ConnectionString = connectionString;
	conn.Open();
	return conn;
}

原始碼:https://github.com/codetuner/Arebis.Web.Mvc.ElmahDashboard/blob/master/ElmahDashboardHostingApp/Areas/MvcElmahDashboard/Code/ElmahDashboardContext.cs

@ElmahMsSqlTarget.cs

這個方法是實作 TargetWithLayout 抽象來的,具體作法請參考 Bibby 大神的文章:http://bibby.be/2012/08/nlog-elamh.html

我只是改用自己的解密連線工廠 (ConnectionFactory.CreateDbConnection) 和 Dapper

protected override void Write(LogEventInfo logEvent)
{
	using (var connection = ConnectionFactory.CreateDbConnection(ConnectionStringName))
	{
		if (connection.State == ConnectionState.Closed)
		{
			connection.Open();
		}
		var time = logEvent.TimeStamp.ToUniversalTime();

		var xdoc = GetXdoc(logEvent, time);

		var userName = string.Empty;

		if (CurrentHttpContext != null && CurrentHttpContext.User.Identity.IsAuthenticated)
		{
			userName = CurrentHttpContext.User.Identity.Name;
		}
		connection.Execute("ELMAH_LogError",
						   new
						   {
							   ErrorId = (Guid) SequentialGuid.NewGuid(),
							   Application = AppSetting.APPLICATION_NAME,
							   Host = Environment.MachineName,
							   Type = "NLog-" + logEvent.Level.Name,
							   Source = logEvent.LoggerName,
							   Message = logEvent.FormattedMessage,
							   User = userName,
							   AllXml = xdoc.ToString(),
							   StatusCode = 0,
							   TimeUtc = time
						   },
						   commandType: CommandType.StoredProcedure);
	}
}

 

處理完後,就能使用加密後的連線字串了,基本上有用到 Elmah 連線字串的物件的人都要處理

 

參考資料:

https://dotblogs.com.tw/mrkt/2016/05/27/013356
http://kevintsengtw.blogspot.tw/2016/05/aspnet-mvc-elmah-dashboard-elmah-sql.html

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo