ASP.NET MVC HandleError


110

[HandleError]asp.net MVCプレビュー5のフィルターについて教えてください。
Web.configファイルにcustomErrorsを設定しました

<customErrors mode="On" defaultRedirect="Error.aspx">
  <error statusCode="403" redirect="NoAccess.htm"/>
  <error statusCode="404" redirect="FileNotFound.htm"/>
</customErrors>

そして、次のように[HandleError]をコントローラークラスの上に置きます。

[HandleError]
public class DSWebsiteController: Controller
{
    [snip]
    public ActionResult CrashTest()
    {
        throw new Exception("Oh Noes!");
    }
}

次に、コントローラーにこのクラスを継承させ、CrashTest()を呼び出します。Visual Studioはエラーで停止し、f5を押して続行すると、Error.aspx?aspxerrorpath = / sxi.mvc / CrashTestに転送されます(sxiは使用されているコントローラーの名前です。もちろん、パスが見つからないため、 「「/」アプリケーションでのサーバーエラー。」404。

このサイトはプレビュー3から5に移植されました。エラー処理を除くすべてが実行されます(移植する作業はそれほど多くありませんでした)。完全に新しいプロジェクトを作成すると、エラー処理が機能するようです。

アイデア?

-注-
この質問には現在3Kを超えるビューがあるため、私が現在使用しているもの(ASP.NET MVC 1.0)を使用することは有益だと思いました。では、MVCのcontribプロジェクトあなたはおそらくあまりにもそれをチェックアウトする必要があります「RescueAttribute」と呼ばれる華麗な属性があります。)


回答:


158
[HandleError]

HandleError属性のみをクラス(または、問題のアクションメソッド)に提供すると、未処理の例外が発生すると、MVCは最初にコントローラーのビューフォルダーで「エラー」という名前の対応するビューを探します。そこに見つからない場合は、共有ビューフォルダ(デフォルトではError.aspxファイルが含まれているはずです)を探します。

[HandleError(ExceptionType = typeof(SqlException), View = "DatabaseError")]
[HandleError(ExceptionType = typeof(NullReferenceException), View = "LameErrorHandling")]

追加の属性を積み上げて、探している例外のタイプに関する特定の情報を表示することもできます。その時点で、エラーをデフォルトの「エラー」ビュー以外の特定のビューに向けることができます。

詳細については、Scott Guthrieのブログ投稿をご覧ください。


1
詳しい情報をありがとう。私は何が悪かったのかわかりませんが、新しいプロジェクトを作成し、そこにあるすべての既存のビュー、コントローラー、モデルを移植したところ、現在は機能しています。ただし、選択的なビューについては知りませんでした。
Boris Callens、

これらの例外のログが必要な場合、ビューの後ろに分離コードを追加するのにこれは許容できる場所ですか?
Peter J

6
象徴的な、これがあなたのコメントへの私の「遅くならないよりも良い」返信です:代わりに、HandleErrorAttributeをサブクラス化して、その "OnException"メソッドをオーバーライドできます:次に、必要なロギングまたはカスタムアクションを挿入します。その後、例外を完全に処理する(context.ExceptionHandledをtrueに設定する)か、このために基本クラスの独自のOnExceptionメソッドに延期することができます。ここではこれで役立つかもしれない優れた記事があります:blog.dantup.me.uk/2009/04/...
粉化

私は、コントローラがたくさんあるので、私は、この内部を扱うことができるglobal.asaxように、このユーザーにメッセージを表示するには?
shaijut 2016

@PartialViewと同じエラーページを使用して、例外発生後にモーダルダイアログに表示するのはどうですか?回答の例を教えていただけますか?私が達成したいことは、MVCのPartialViewを使用したグローバルエラー処理で説明されました。
Jack

23

また、httpエラーコードを500に設定しないエラーは、

(例:UnauthorizedAccessException)

HandleErrorフィルターでは処理されません。


1
正しいですが、MVC contribのRescueAttributeを確認してください(OPのリンク)
Boris Callens

14

500へのhttpエラーコードの解決策これは[ERROR]と呼ばれる属性で、アクションに配置します

public class Error: System.Web.Mvc.HandleErrorAttribute
{
    public override void OnException(System.Web.Mvc.ExceptionContext filterContext)
    {

            if (filterContext.HttpContext.IsCustomErrorEnabled)
            {
                filterContext.ExceptionHandled = true;

            }
            base.OnException(filterContext);
            //OVERRIDE THE 500 ERROR  
           filterContext.HttpContext.Response.StatusCode = 200;
    }

    private static void RaiseErrorSignal(Exception e)
    {
        var context = HttpContext.Current;
      // using.Elmah.ErrorSignal.FromContext(context).Raise(e, context);
    } 

}

//例:

[Error]
[HandleError]
[PopulateSiteMap(SiteMapName="Mifel1", ViewDataKey="Mifel1")]
public class ApplicationController : Controller
{
}

12

MVCの属性は、getおよびpostメソッドでのエラー処理に非常に役立ちます。また、ajax呼び出しを追跡します

アプリケーションに基本コントローラーを作成し、それをメインコントローラー(EmployeeController)に継承します。

パブリッククラスEmployeeController:BaseController

以下のコードをベースコントローラに追加します。

/// <summary>
/// Base Controller
/// </summary>
public class BaseController : Controller
{       
    protected override void OnException(ExceptionContext filterContext)
    {
        Exception ex = filterContext.Exception;

        //Save error log in file
        if (ConfigurationManager.AppSettings["SaveErrorLog"].ToString().Trim().ToUpper() == "TRUE")
        {
            SaveErrorLog(ex, filterContext);
        }

        // if the request is AJAX return JSON else view.
        if (IsAjax(filterContext))
        {
            //Because its a exception raised after ajax invocation
            //Lets return Json
            filterContext.Result = new JsonResult()
            {
                Data = Convert.ToString(filterContext.Exception),
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };
        }
        else
        {
            filterContext.ExceptionHandled = true;
            filterContext.HttpContext.Response.Clear();

            filterContext.Result = new ViewResult()
            {
                //Error page to load
                ViewName = "Error",
                ViewData = new ViewDataDictionary()
            };

            base.OnException(filterContext);
        }
    }

    /// <summary>
    /// Determines whether the specified filter context is ajax.
    /// </summary>
    /// <param name="filterContext">The filter context.</param>
    private bool IsAjax(ExceptionContext filterContext)
    {
        return filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest";
    }

    /// <summary>
    /// Saves the error log.
    /// </summary>
    /// <param name="ex">The ex.</param>
    /// <param name="filterContext">The filter context.</param>
    void SaveErrorLog(Exception ex, ExceptionContext filterContext)
    {
        string logMessage = ex.ToString();

        string logDirectory = Server.MapPath(Url.Content("~/ErrorLog/"));

        DateTime currentDateTime = DateTime.Now;
        string currentDateTimeString = currentDateTime.ToString();
        CheckCreateLogDirectory(logDirectory);
        string logLine = BuildLogLine(currentDateTime, logMessage, filterContext);
        logDirectory = (logDirectory + "\\Log_" + LogFileName(DateTime.Now) + ".txt");

        StreamWriter streamWriter = null;
        try
        {
            streamWriter = new StreamWriter(logDirectory, true);
            streamWriter.WriteLine(logLine);
        }
        catch
        {
        }
        finally
        {
            if (streamWriter != null)
            {
                streamWriter.Close();
            }
        }
    }

    /// <summary>
    /// Checks the create log directory.
    /// </summary>
    /// <param name="logPath">The log path.</param>
    bool CheckCreateLogDirectory(string logPath)
    {
        bool loggingDirectoryExists = false;
        DirectoryInfo directoryInfo = new DirectoryInfo(logPath);
        if (directoryInfo.Exists)
        {
            loggingDirectoryExists = true;
        }
        else
        {
            try
            {
                Directory.CreateDirectory(logPath);
                loggingDirectoryExists = true;
            }
            catch
            {
            }
        }

        return loggingDirectoryExists;
    }

    /// <summary>
    /// Builds the log line.
    /// </summary>
    /// <param name="currentDateTime">The current date time.</param>
    /// <param name="logMessage">The log message.</param>
    /// <param name="filterContext">The filter context.</param>       
    string BuildLogLine(DateTime currentDateTime, string logMessage, ExceptionContext filterContext)
    {
        string controllerName = filterContext.RouteData.Values["Controller"].ToString();
        string actionName = filterContext.RouteData.Values["Action"].ToString();

        RouteValueDictionary paramList = ((System.Web.Routing.Route)(filterContext.RouteData.Route)).Defaults;
        if (paramList != null)
        {
            paramList.Remove("Controller");
            paramList.Remove("Action");
        }

        StringBuilder loglineStringBuilder = new StringBuilder();

        loglineStringBuilder.Append("Log Time : ");
        loglineStringBuilder.Append(LogFileEntryDateTime(currentDateTime));
        loglineStringBuilder.Append(System.Environment.NewLine);

        loglineStringBuilder.Append("Username : ");
        loglineStringBuilder.Append(Session["LogedInUserName"]);
        loglineStringBuilder.Append(System.Environment.NewLine);

        loglineStringBuilder.Append("ControllerName : ");
        loglineStringBuilder.Append(controllerName);
        loglineStringBuilder.Append(System.Environment.NewLine);

        loglineStringBuilder.Append("ActionName : ");
        loglineStringBuilder.Append(actionName);
        loglineStringBuilder.Append(System.Environment.NewLine);

        loglineStringBuilder.Append("----------------------------------------------------------------------------------------------------------");
        loglineStringBuilder.Append(System.Environment.NewLine);

        loglineStringBuilder.Append(logMessage);
        loglineStringBuilder.Append(System.Environment.NewLine);
        loglineStringBuilder.Append("==========================================================================================================");

        return loglineStringBuilder.ToString();
    }

    /// <summary>
    /// Logs the file entry date time.
    /// </summary>
    /// <param name="currentDateTime">The current date time.</param>
    string LogFileEntryDateTime(DateTime currentDateTime)
    {
        return currentDateTime.ToString("dd-MMM-yyyy HH:mm:ss");
    }

    /// <summary>
    /// Logs the name of the file.
    /// </summary>
    /// <param name="currentDateTime">The current date time.</param>
    string LogFileName(DateTime currentDateTime)
    {
        return currentDateTime.ToString("dd_MMM_yyyy");
    }

}

================================================

ディレクトリを検索します:Root / App_Start / FilterConfig.cs

コードの下に追加:

/// <summary>
/// Filter Config
/// </summary>
public class FilterConfig
{
    /// <summary>
    /// Registers the global filters.
    /// </summary>
    /// <param name="filters">The filters.</param>
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    }
}

AJAXエラーを追跡:

レイアウトページの読み込み時にCheckAJAXError関数を呼び出します。

function CheckAJAXError() {
    $(document).ajaxError(function (event, jqXHR, ajaxSettings, thrownError) {

        var ex;
        if (String(thrownError).toUpperCase() == "LOGIN") {
            var url = '@Url.Action("Login", "Login")';
            window.location = url;
        }
        else if (String(jqXHR.responseText).toUpperCase().indexOf("THE DELETE STATEMENT CONFLICTED WITH THE REFERENCE CONSTRAINT") >= 0) {

            toastr.error('ReferanceExistMessage');
        }
        else if (String(thrownError).toUpperCase() == "INTERNAL SERVER ERROR") {
            ex = ajaxSettings.url;
            //var url = '@Url.Action("ErrorLog", "Home")?exurl=' + ex;
            var url = '@Url.Action("ErrorLog", "Home")';
            window.location = url;
        }
    });
};

あなたはAJAXリクエストの例外の詳細を漏らしています、あなたはいつもそれを望んでいるわけではありません。ログコードはスレッドセーフではありません。エラービューがあると想定し、応答コードを変更せずにそれを返します。次に、JavaScriptで特定のエラー文字列を確認します(ローカリゼーションはどうですか?)。基本的に、既存の回答で既に述べられているOnException例外を処理するためのオーバーライド」を繰り返していますが、そのかなり悪い実装を示しています。
CodeCaster 2016

@ School.Resource.Messages.ReferanceExistパラメータとは何ですか?
Jack

@CodeCaster ASP.NET MVCのAJAXでこのような種類のエラー処理メソッドを使用するためのより良い方法を知っていますか?何か助けてください?
Jack

HTTPが意図されているように、400または500を返します。応答本文の特定の文字列を掘り下げないでください。
CodeCaster '20

@CodeCaster この問題に関して、MVCでPartialViewを使用したグローバルエラー処理をご覧ください。
Jack

4

Error.aspxがありません:)プレビュー5では、これはViews / Sharedフォルダーにあります。新しいプレビュー5プロジェクトからコピーするだけです。


返信いただきありがとうございます。すでにError.aspxページをコピーしています。確かに、私が普段は忘れていたかもしれませんが、今回はそうではありませんでした。:P
ボリス・カレンス、

-1
    [HandleError]
    public class ErrorController : Controller
    {        
        [AcceptVerbs(HttpVerbs.Get)]
        public ViewResult NotAuthorized()
        {
            //401
            Response.StatusCode = (int)HttpStatusCode.Unauthorized;

        return View();
    }

    [AcceptVerbs(HttpVerbs.Get)]
    public ViewResult Forbidden()
    {
        //403
        Response.StatusCode = (int)HttpStatusCode.Forbidden;

        return View();
    }

    [AcceptVerbs(HttpVerbs.Get)]
    public ViewResult NotFound()
    {
        //404
        Response.StatusCode = (int)HttpStatusCode.NotFound;
        return View();
    }

    public ViewResult ServerError()
    {
        //500
        Response.StatusCode = (int)HttpStatusCode.NotFound;
        return View();
    }

}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.