ASP.NET MVC5で例外が文字化け


やりたかったこと

Controller以外で発生した例外を
Global.asax.csのApplication_Errorイベントに集約させて
エラー内容(厳密にはServer.GetLastError()のMessage)をNLogでログ出力をしたかった。

試したこと

ソースファイルのエンコーディングおよびリクエスト、レスポンス、レスポンスヘッダをUTF-8として見なすようWeb.configに次の記述を追加


<configuration>
  <system.web>
    <globalization fileEncoding="utf-8" requestEncoding="utf-8" responseEncoding="utf-8" responseHeaderEncoding="utf-8" />
  </system.web>
・・・

NLogが出力するファイルのエンコーディングもUTF-8にした

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <targets>
    <target name="errorlog"
     xsi:type="File"
     layout="${longdate} [${threadid:padding=8}] [${uppercase:${level:padding=-5}}] ${callsite}() ${message} ${exception:format=tostring}"
     fileName="${basedir}/APP_Data/nlog/ErrorLog.txt" 
     archiveFileName="${basedir}/App_Data/nlog/ErrorLog.{#####}.txt"
     maxArchiveFiles="100"
     archiveAboveSize="102400" 
     archiveNumbering="Sequence"
     archiveEvery="Day"
     concurrentWrites="true"
     keepFileOpen="false"
     encoding="UTF-8" />
  </targets>
  <rules>
    <logger name="ExceptionHandler" minlevel="Debug" writeTo="errorlog" />
  </rules>
</nlog>

これで行けるかと思いGlobal.asax.csで次のような処理を作りログを吐かせてみた

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using NLog;

namespace Hoge
{
    public class MvcApplication : System.Web.HttpApplication
    {
        private static Logger logger = NLog.LogManager.GetLogger("ExceptionHandler");
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
        protected void Application_Error(object sender, EventArgs e)
        {
            if (Server != null)
            {
                var ex = Server.GetLastError();
                logger.Fatal(ex);
            }
        }
    }
}

結果

2018-11-20 18:49:37.6676 [       6] [FATAL] Hoge.MvcApplication.Application_Error() System.Web.HttpException (0x80004005): !baRrz!A public action method 'Fuga' was not found on controller 'Hoge.Controllers.HogeController'. 表©鷗字㌍ 表!
   場所 System.Web.Mvc.Controller.HandleUnknownAction(String actionName)
   場所 System.Web.Mvc.Controller.<>c.<BeginExecuteCore>b__152_1(IAsyncResult asyncResult, ExecuteCoreState innerState)
(以下スタックトレース)

うん。エラー内容が化けている!

これは困った

とりあえず安直に文字化けをコピペしGoogle先生に聞いてみると、
Qiitaで関連した記事が見つかった!

どうやらライブラリの問題っぽい。

実際に確認してみる


説明が既にバグってやがります。
説明文のバグり具合から、バージョンは3.2.4と3.2.5がNGに見えます。
3.2.6は正常に見える。

Microsoft.AspNet.Mvc.jaを現在の最新安定版(3.2.6)にアップデートしてみたら
Razor.jaとWebpages.jaも勝手にアップデートされた。

結果

2018-11-20 18:55:40.0646 [       8] [FATAL] Hoge.MvcApplication.Application_Error() System.Web.HttpException (0x80004005): コントローラー 'Hoge.Controllers.HogeController' にパブリック アクション メソッド 'Fuga' が見つかりませんでした。
   場所 System.Web.Mvc.Controller.HandleUnknownAction(String actionName)
   場所 System.Web.Mvc.Controller.<>c.<BeginExecuteCore>b__152_1(IAsyncResult asyncResult, ExecuteCoreState innerState)

これで、文字化けせずにログが出力されたので無事解決。