在網站系統上線之後,網站的營運也是相當重要的一環,然而不可能有沒有線上異常的程式碼,因此收集網站的錯誤資訊也是很重要的一門功課,透過對錯誤資訊的分析,我們可以找出錯誤產生的原因並修正它,同時也可以避免掉有一些重大的Bug沒被發現,而今天要向大家介紹的就是一套專門用來收集並呈現錯誤資訊的Library,我們要透過它來幫助我們管理線上的錯誤訊息。
大家可以從Github ApiSample - Tag Day14取得程式碼開始今天的練習
※安裝Elmah.MVC
現在要安裝Elmah已經相當的方便了,又尤其在Nuget出現之後,我們幾乎連修改Web.config的動作都不需要,就可以全自動的安裝完套件並成功啟用。而Elmah.Mvc是專門替Asp.Net MVC整合好Elmah的套件,它將我們之前在套用Asp.Net MVC時所常遇到的情境都替我們處理掉了,包含Routing、HandleErrorAttribute等,非常的方便。
在WebSite上使用Nuget安裝Elmah.Mvc
安裝完成後會發現Web.Config多了一些設定,但對我們比較有影響的應該是AppSettings所增加的以下幾個
<!--代表是否啟用Elmah.mvc的Handler-->
<add key="elmah.mvc.disableHandler" value="false" />
<!--代表是否使用HandleErrorAttribute-->
<add key="elmah.mvc.disableHandleErrorFilter" value="false" />
<!--連接Elmah是否需要驗證-->
<add key="elmah.mvc.requiresAuthentication" value="false" />
<!--使用停用預設的Route-->
<add key="elmah.mvc.IgnoreDefaultRoute" value="false" />
<!--若啟用驗證,允許的角色-->
<add key="elmah.mvc.allowedRoles" value="*" />
<!--若啟用驗證,允許的使用者-->
<add key="elmah.mvc.allowedUsers" value="*" />
<!--自定的Elmah路徑-->
<add key="elmah.mvc.route" value="elmah" />
我們可以連接到/elmah打開Elmah的網頁
延伸閱讀:
* mrkt的程式學習筆記 - elmah
※將錯誤資訊儲存到Sql Server中
預設若沒有做任何設定的話,Elmah是將錯誤儲存到記憶體中的,隨著網站重新啟動這些錯誤資訊就會消失,為了方便對於線上錯誤的持續追蹤,我們通常會將錯誤資訊儲存為Xml或是Sql Server中,而為了更方便的進行分析和統計,因此本次的範例將選擇儲存到Sql Server,而在開發環境將使用LocalDB作為範例。
連接到ApiSample,建立新資料庫
資料庫名稱為ExceptionDB
修改資料庫檔案儲存路徑
與網站資料庫一樣,放在C:\LocalDB\ApiSample下
從官方網站取得SqlScript,建立Elmah所需要使用的Table和StoredProcedure
https://code.google.com/p/elmah/downloads/detail?name=ELMAH-1.2-db-SQLServer.sql
在網站新增ConnectionString,讓Elmah連線使用
<add name="ExceptionDB"
providerName="System.Data.SqlClient"
connectionString="Data Source=(LocalDb)\ApiSample;Initial Catalog=ExceptionDB;Integrated Security=SSPI;AttachDBFilename=C:\LocalDB\ApiSample\ExceptionDB.mdf" />
在web.config找到elmah區段,新增ErrorLog,將資料存到SqlServer
<elmah>
<errorLog type="Elmah.SqlErrorLog, Elmah"
connectionStringName="ExceptionDB"
applicationName="ApiSample" />
</elmah>
嘗試在網站觸發錯誤之後,可以看到錯誤資料成功的寫入資料庫
※限定IP存取Elmah
由於若沒有將錯誤資訊限定允許內部人員查看,開放在網路上是很危險的行為,有可能被當作系統漏洞來進行攻擊,因此限制存取是相當重要的。而Elmah其實內建支援Asp.Net的Role、User機制,可以透過config來設定,不過由於我們是Api系統,不想要再另外做出一個登入的UI介面,因此將介紹如何限定允許的ip連接Elmah。
註: 這個方法其實算是一個Trick,最保險的做法還是實作登入介面來確保安全性!由於我們沒辦法透過直接在Elmah的Controller加上Filter,因此透過複寫Route的方式來實作
透過修改config關閉elmah的預設路由,取消預設的入口
<add key="elmah.mvc.IgnoreDefaultRoute" value="false" />
在Extensions專案新增IPConstraint,增加Route的限制條件,並可以指定允許的IP
public class IPConstraint : IRouteConstraint
{
private string[] ipList = new string[] { };
public IPConstraint(string allowedIps)
{
ipList = allowedIps.Split(',', ';');
}
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
string clientIp = httpContext.Request.UserHostAddress;
if (!ipList.Contains(clientIp))
{
throw new UnauthorizedAccessException("Disallowed Client IP!");
}
return true;
}
}
在網站的RouteConfig增加以下Routing,並指定只能允許的IP連結
var namespaces = new[] { "Elmah.Mvc" };
var elmahRoute = "ErrorBorad";
routes.MapRoute(
"Elmah.Override",
string.Format("{0}/{{resource}}", elmahRoute),
new
{
controller = "Elmah",
action = "Index",
resource = UrlParameter.Optional
},
new { resource = new IPConstraint("::1;127.0.0.1") },
namespaces);
routes.MapRoute(
"Elmah.Override.Detail",
string.Format("{0}/detail/{{resource}}", elmahRoute),
new
{
controller = "Elmah",
action = "Detail",
resource = UrlParameter.Optional
},
new { resource = new IPConstraint("::1;127.0.0.1") },
namespaces);
在config找到elmah區段,將允許遠端連線打開
<elmah>
<security allowRemoteAccess="true" />
<errorLog type="Elmah.SqlErrorLog, Elmah"
connectionStringName="ExceptionDB"
applicationName="ApiSample" />
</elmah>
若是不允許的IP嘗試連線時,系統就會拋出異常囉!
延伸閱讀
* ASP.NET MVC Route 自訂限制條件(constraints)的技巧
※本日小結
透過Elmah,我們可以清楚的知道網站線上的異常發生狀況,並可以透過這些資訊來修正我們的程式,提高系統的穩定性及安全性,未來我還將再繼續介紹如何透過這些資訊來監控我們網站的健康狀況,關於今天的內容,歡迎大家一起討論^_^