Özel hata sayfaları ASP.NET MVC 4'te nasıl çalışır


247

500, 404 ve 403 için gösterilen özel bir hata sayfası istiyorum. İşte yaptım:

  1. Web.config dosyasındaki özel hataları aşağıdaki gibi etkinleştirin:

    <customErrors mode="On" 
                  defaultRedirect="~/Views/Shared/Error.cshtml">
    
        <error statusCode="403" 
               redirect="~/Views/Shared/UnauthorizedAccess.cshtml" />
    
        <error statusCode="404" 
               redirect="~/Views/Shared/FileNotFound.cshtml" />
    
    </customErrors>
  2. Kayıtlı HandleErrorAttributebir küresel eylem filtre olarak FilterConfigaşağıdaki gibi sınıfta:

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new CustomHandleErrorAttribute());
        filters.Add(new AuthorizeAttribute());
    }
  3. Yukarıdaki mesajların her biri için özel bir hata sayfası oluşturuldu. 500 için varsayılan olan kutunun dışında zaten mevcuttu.

  4. Her özel hata sayfası görünümünde, sayfa modelinin olduğu bildirildi System.Web.Mvc.HandleErrorInfo

500 için özel hata sayfasını gösterir. Diğerleri için öyle değil.

Kaçırdığım bir şey var mı?

Sınıf OnExceptionyöntemindeki kodu okurken özel hataların görüntülenmesi için tek şey yok gibi görünüyor HandleErrorAttributeve sadece 500 işliyor.

Diğer hataları işlemek için ne yapmam gerekir?


21
Bu kurulumda garip olan şey, denetleyici eylemlerine değil görünümlere yönlendirmenizdir. Örneğin, kimin bu görüşleri sunması ve bir modelden geçmesi gerekiyor? Sadece düşünüyorum.
Oliver

2
Buradaki yanıtların çoğu ya tüm vakaları işlemez ya da web sunucusunun "yanlış" bir şekilde yanıt vermesine neden olur, yani bir hata yanıtı döndürmek yerine bir hata sayfasına yönlendirme. Sunucunun web sunucularından beklenen bir şekilde yanıt vermesini önemsiyorsanız , burada bu konuda oldukça ayrıntılı bir makale var: benfoster.io/blog/aspnet-mvc-custom-error-pages . Buradaki cevaplar kadar basit olmadığı konusunda uyarınız, bu yüzden kolay bir cevap istiyorsanız aşağıdaki cevaplardan birini kullanın.
rdans

1
Burada asp.net hata işleme için çeşitli teknikler hakkında başka bir harika makale dusted.codes/…
Godsayah

Yanıtlar:


352

Geçerli kurulum (MVC3 üzerinde, ama hala geçerli olduğunu düşünüyorum) sahip bir dayanır ErrorController, bu yüzden kullanıyorum:

<system.web>
    <customErrors mode="On" defaultRedirect="~/Error">
      <error redirect="~/Error/NotFound" statusCode="404" />
    </customErrors>
</system.web>

Ve denetleyici aşağıdakileri içerir:

public class ErrorController : Controller
{
    public ViewResult Index()
    {
        return View("Error");
    }
    public ViewResult NotFound()
    {
        Response.StatusCode = 404;  //you may want to set this to 200
        return View("NotFound");
    }
}

Ve görüşlerinizi tam da uyguladığınız gibi. Uygulama hata ayıklama modunda ise yığın izleme ve hata bilgilerini göstermek için olsa da, biraz mantık ekleme eğilimindedir. Error.cshtml şuna benzer:

@model System.Web.Mvc.HandleErrorInfo
@{
    Layout = "_Layout.cshtml";
    ViewBag.Title = "Error";
}
<div class="list-header clearfix">
    <span>Error</span>
</div>
<div class="list-sfs-holder">
    <div class="alert alert-error">
        An unexpected error has occurred. Please contact the system administrator.
    </div>
    @if (Model != null && HttpContext.Current.IsDebuggingEnabled)
    {
        <div>
            <p>
                <b>Exception:</b> @Model.Exception.Message<br />
                <b>Controller:</b> @Model.ControllerName<br />
                <b>Action:</b> @Model.ActionName
            </p>
            <div style="overflow:scroll">
                <pre>
                    @Model.Exception.StackTrace
                </pre>
            </div>
        </div>
    }
</div>

7
Bu Pablo için Global.asax'ınızdaki Application_Error öğesine bir şey koymak zorunda mıydınız?
Alicia

12
Denetleyicideki kod benim deneyimimden yürütülmüş gibi görünmüyor. MVC4 - farklı bir denetleyiciye bir System.Exception atmak Error.cshtml dosyasını oluşturur, ancak ErrorController aracılığıyla gerçekleştirmez. Bunu yaşayan başka biri var mı?
Nilzor

53
Bunu yararlı bulan, ancak daha fazla bağlama ihtiyaç duyan herkes için; <customErrors> etiketi, web.config dosyasındaki <system.web> içine girer.
gooberverse

7
Diğerleri için Güncelleştirme - Ben çünkü görünüşte sorunum oluyordu redirectMode="ResponseRewrite"üzerinde CustomerErrorseleman
KyleMit

42
Tanrı'nın sevgisi için lütfen //you may want to set this to 200koddaki yorumu görmezden gelin . BÖYLE YAPMA!
Dementic

40

Pablo çözüm yaptım ve her zaman hata (MVC4) vardı

'Hata' görünümü veya yöneticisi bulunamadı veya hiçbir arama motoru aranan konumu desteklemiyor.

Bundan kurtulmak için çizgiyi kaldırın

 filters.Add(new HandleErrorAttribute());

FilterConfig.cs içinde


Bunu çözmek için her yere baktım. Bu nihayet cevap verdi. Neden yaptığını biliyordum ama benim için, diğer insanların söyledikleri gibi ciddi bir şekilde düşünmeden yapamadım. Bunu işaret ettiğiniz için teşekkür ettiğimde 360Airwalk'un acısını paylaştığımı hayal ediyorum. Efsane!
Adam

Bu bir seçenektir ve Hata denetleyicisi iyi çalışır. Ancak, filtreleri FilterConfig.cs dosyasına kaydettiğinizde, paylaşılan ve orijinal denetleyicilerin görünüm klasörlerinde Error.cshtml dosyasını arar. Error.cshtml dosyasını, özel ErrorController'ımız dışında bir şeyle değiştirdiğinizde. Ancak bu kaydı ekleyebileceğiniz bir yer var ve global.asax.cs. Global.asax.cs içindeki RegisterGlobalFilters (GlobalFilterCollection filtreleri) işlevinde belirtilen satırı ekler ve FilterConfig.cs dosyasından kaldırırsanız çalışır.
isaolmez

Filtre kayıtlarının sırası ile ilgili olduğunu düşünüyorum. Hata denetleyicisini saklayın ve filtre kaydını global.asax.cs dosyasına taşıyın. public static void RegisterGlobalFilters (GlobalFilterCollection filtreleri) {filters.Add (yeni HandleErrorAttribute ()); }
isaolmez

24

Gönderilen diğer çözümlerden daha az kodlama gerektiren bir şey yapıyorum.

İlk olarak, web.config dosyamda aşağıdakiler var:

<customErrors mode="On" defaultRedirect="~/ErrorPage/Oops">
   <error redirect="~/ErrorPage/Oops/404" statusCode="404" />
   <error redirect="~/ErrorPage/Oops/500" statusCode="500" />
</customErrors>

Ve denetleyici (/Controllers/ErrorPageController.cs) aşağıdakileri içerir:

public class ErrorPageController : Controller
{
    public ActionResult Oops(int id)
    {
        Response.StatusCode = id;

        return View();
    }
}

Ve son olarak, görünüm aşağıdakileri içerir (basitlik için soyulmuş, ancak kapsayıcı olabilir:

@{ ViewBag.Title = "Oops! Error Encountered"; }

<section id="Page">
  <div class="col-xs-12 well">
    <table cellspacing="5" cellpadding="3" style="background-color:#fff;width:100%;" class="table-responsive">
      <tbody>
        <tr>
          <td valign="top" align="left" id="tableProps">
            <img width="25" height="33" src="~/Images/PageError.gif" id="pagerrorImg">
          </td>
          <td width="360" valign="middle" align="left" id="tableProps2">
            <h1 style="COLOR: black; FONT: 13pt/15pt verdana" id="errortype"><span id="errorText">@Response.Status</span></h1>
          </td>
        </tr>
        <tr>
          <td width="400" colspan="2" id="tablePropsWidth"><font style="COLOR: black; FONT: 8pt/11pt verdana">Possible causes:</font>
          </td>
        </tr>
        <tr>
          <td width="400" colspan="2" id="tablePropsWidth2">
            <font style="COLOR: black; FONT: 8pt/11pt verdana" id="LID1">
                            <hr>
                            <ul>
                                <li id="list1">
                                    <span class="infotext">
                                        <strong>Baptist explanation: </strong>There
                                        must be sin in your life. Everyone else opened it fine.<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Presbyterian explanation: </strong>It's
                                        not God's will for you to open this link.<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong> Word of Faith explanation:</strong>
                                        You lack the faith to open this link. Your negative words have prevented
                                        you from realizing this link's fulfillment.<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Charismatic explanation: </strong>Thou
                                        art loosed! Be commanded to OPEN!<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Unitarian explanation:</strong> All
                                        links are equal, so if this link doesn't work for you, feel free to
                                        experiment with other links that might bring you joy and fulfillment.<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Buddhist explanation:</strong> .........................<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Episcopalian explanation:</strong>
                                        Are you saying you have something against homosexuals?<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Christian Science explanation: </strong>There
                                        really is no link.<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Atheist explanation: </strong>The only
                                        reason you think this link exists is because you needed to invent it.<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Church counselor's explanation:</strong>
                                        And what did you feel when the link would not open?
                                    </span>
                                </li>
                            </ul>
                            <p>
                                <br>
                            </p>
                            <h2 style="font:8pt/11pt verdana; color:black" id="ietext">
                                <img width="16" height="16" align="top" src="~/Images/Search.gif">
                                HTTP @Response.StatusCode - @Response.StatusDescription <br>
                            </h2>
                        </font>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</section>

Bu kadar basit. Daha ayrıntılı hata bilgileri sunmak için kolayca genişletilebilir, ancak ELMAH benim ve statusCode ve statusDescription için genellikle ihtiyacım olan tek şeydir.


"~ / ErrorPage / Oops / 404" .config dosyasındaki yönlendirme muhtemelen "~ / ErrorPage / Oops? 404" olmalıdır? En azından benim için işe yarayan buydu. Belki bu sadece rotaya bağlıdır.
Josh Sutterfield

IIS tarafından atılan bir hata nasıl simüle edilir. 500 veya 504 olsun. ASP.Net MVC - 5 kodu ne yapmak benim özel hata sayfamı test edebilirsiniz IIS istisna benzetmek için
Unbreakable

12

Burada birbirine karışan birkaç adım var gibi görünüyor. Ne yaptığımı sıfırdan ortaya koyacağım.

  1. ErrorPageDenetleyiciyi oluşturma

    public class ErrorPageController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }
    
        public ActionResult Oops(int id)
        {
            Response.StatusCode = id;
            return View();
        }
    }
  2. Bu iki eylem için görünüm ekleyin (sağ tıklayın -> Görünüm Ekle). Bunlar ErrorPage adlı bir klasörde görünmelidir.

  3. İçeride App_Startaçın FilterConfig.csve hata işleme filtresini yorumlayın.

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        // Remove this filter because we want to handle errors ourselves via the ErrorPage controller
        //filters.Add(new HandleErrorAttribute());
    }
  4. Web.config içine aşağıdaki <customerErrors>girişleri ekleyin:System.Web

    <customErrors mode="On" defaultRedirect="~/ErrorPage/Oops">
        <error redirect="~/ErrorPage/Oops/404" statusCode="404" />
        <error redirect="~/ErrorPage/Oops/500" statusCode="500" />
    </customErrors>
  5. Test (tabii ki). Kodunuzda işlenmeyen bir istisna atın ve 500 kimliğine sahip sayfaya gittiğini görün ve ardından 404'ü görmek için var olmayan bir sayfaya URL kullanın.


Bu hatayı alıyordum An exception occurred while processing your request. Additionally, another exception occurred while executing the custom error page for the first exception. The request has been terminated.Kodunuzdan aldığım tek şey web.config dosyasında, ekledim <error redirect = "~/ControllerName/ActionName" statusCode="404"/>ve iyi çalıştı :) Kodun geri kalanı @ Pablo'nun cevabından geliyordu. MVC 5 ve varlık çerçevesi 6 kullanıyorum filters.Add(new HandleErrorAttribute()).FilterConfig.cs
sumedha

IIS tarafından atılan bir hata nasıl simüle edilir. 500 veya 504 olsun. ASP.Net MVC - 5 kodu ne yapmak benim özel hata sayfamı test edebilirsiniz IIS istisna benzetmek için
Unbreakable

Ayrıca, ele alınmayan istisna atma (adım 5). Kodlama konusunda yeniyim lütfen yönlendirin.
kırılmaz

Hala benim için çalışmıyor mu? Yönlendirme ne olacak? Hata için Yönlendirme sayfasını da eklemem gerekir mi? Sayfayı vurursam : localhost: 84 / Enforcer / blah Ben şu adrese yönlendirilirim: localhost: 84 / Enforcer / Enforcer / Hata / NotFound? Aspxerrorpath = /… Hata sayfası, Asp.NET tarafından sağlanan standart bir hata sayfasına benziyor. Herhangi bir fikir?
Radek Strugalski

Webconfig dosyasındaki customerrors öğesi bunu alıştırıyor olmalıdır. (Proje tarafından oluşturulan) varsayılan yol kodunuz iyi çalışmalıdır.
VictorySaber

11

Global.asax.cs dosyasını kullanmanızı tavsiye ederim.

 protected void Application_Error(Object sender, EventArgs e)
{
    var exception = Server.GetLastError();
    if (exception is HttpUnhandledException)
    {
        Server.Transfer("~/Error.aspx");
    }
    if (exception != null)
    {
        Server.Transfer("~/Error.aspx");
    }
    try
    {
        // This is to stop a problem where we were seeing "gibberish" in the
        // chrome and firefox browsers
        HttpApplication app = sender as HttpApplication;
        app.Response.Filter = null;
    }
    catch
    {
    }
}

1
MVC bir Server.Transfer () yapabileceğini düşünmüyordu. OP'nin karma bir site olduğunu düşünüyor musunuz?
Rap

1
mvc'de neden Application_Error kullanmalıyız? Yönlendirme URL'si seçenekleriyle [işleyici] özelliği gibi seçeneklerimiz var. Bunun application_error ile belirli bir avantajı var mı?
Kurkula

MVC'de HandleErrorAttribute kullanmalıyız ve OnException yöntemini geçersiz kılarak bunları çok daha iyi bir şekilde ele alabiliriz
Kumar Lachhani

7

Maxspan tarafından gönderilen cevabı temel alarak GitHub'da tüm çalışma parçalarını gösteren minimal bir örnek proje hazırladım .

Temel olarak, istisnayı durdurmak ve bize özel bir hata sayfasına yönlendirme (veya daha doğru bir şekilde aktarma isteği ) fırsatı vermek Application_Erroriçin global.asax.cs dosyasına bir yöntem ekliyoruz .

    protected void Application_Error(Object sender, EventArgs e)
    {
        // See http://stackoverflow.com/questions/13905164/how-to-make-custom-error-pages-work-in-asp-net-mvc-4
        // for additional context on use of this technique

        var exception = Server.GetLastError();
        if (exception != null)
        {
            // This would be a good place to log any relevant details about the exception.
            // Since we are going to pass exception information to our error page via querystring,
            // it will only be practical to issue a short message. Further detail would have to be logged somewhere.

            // This will invoke our error page, passing the exception message via querystring parameter
            // Note that we chose to use Server.TransferRequest, which is only supported in IIS 7 and above.
            // As an alternative, Response.Redirect could be used instead.
            // Server.Transfer does not work (see https://support.microsoft.com/en-us/kb/320439 )
            Server.TransferRequest("~/Error?Message=" + exception.Message);
        }

    }

Hata Denetleyicisi:

/// <summary>
/// This controller exists to provide the error page
/// </summary>
public class ErrorController : Controller
{
    /// <summary>
    /// This action represents the error page
    /// </summary>
    /// <param name="Message">Error message to be displayed (provided via querystring parameter - a design choice)</param>
    /// <returns></returns>
    public ActionResult Index(string Message)
    {
        // We choose to use the ViewBag to communicate the error message to the view
        ViewBag.Message = Message;
        return View();
    }

}

Hata sayfası Görünümü:

<!DOCTYPE html>

<html>
<head>
    <title>Error</title>
</head>
<body>

    <h2>My Error</h2>
    <p>@ViewBag.Message</p>
</body>
</html>

FilterConfig.csfilters.Add(new HandleErrorAttribute()) içinde devre dışı bırakmak / kaldırmak dışında başka bir şey yoktur

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        //filters.Add(new HandleErrorAttribute()); // <== disable/remove
    }
}

Uygulanması çok basit olsa da, bu yaklaşımda gördüğüm tek dezavantaj, hedef hata sayfasına istisna bilgileri sunmak için querystring kullanmaktır.


3

Her şeyi ayarladım, ancak her şey yerel geliştirme sunucularında iyi çalışmasına rağmen, hazırlama sunucumuzdaki durum kodu 500 için uygun hata sayfalarını hala göremedim.

Bana yardımcı olan Rick Strahl'ın bu blog gönderisini buldum .

Response.TrySkipIisCustomErrors = true;Özel hata işleme koduma eklemem gerekiyordu .


@ Shaun314 Yani bu kodu nereye koydunuz? İsteği işleyen eylemde. Bu blog gönderisinde örnekleri görebilirsiniz.
DCShannon

2

İşte benim çözümüm. Kullanım [ExportModelStateToTempData] / [ImportModelStateFromTempData] Bence rahatsız.

~ / Görüntüleme / Ev / Error.cshtml:

@{
    ViewBag.Title = "Error";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Error</h2>
<hr/>

<div style="min-height: 400px;">

    @Html.ValidationMessage("Error")

    <br />
    <br />

    <button onclick="Error_goBack()" class="k-button">Go Back</button>
    <script>
        function Error_goBack() {
            window.history.back()
        }
    </script>

</div>

~ / Kontrolörler / HomeController.sc:

public class HomeController : BaseController
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult Error()
    {
        return this.View();
    }

    ...
}

~ / Kontrolörler / BaseController.sc:

public class BaseController : Controller
{
    public BaseController() { }

    protected override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Result is ViewResult)
        {
            if (filterContext.Controller.TempData.ContainsKey("Error"))
            {
                var modelState = filterContext.Controller.TempData["Error"] as ModelState;
                filterContext.Controller.ViewData.ModelState.Merge(new ModelStateDictionary() { new KeyValuePair<string, ModelState>("Error", modelState) });
                filterContext.Controller.TempData.Remove("Error");
            }
        }
        if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
        {
            if (filterContext.Controller.ViewData.ModelState.ContainsKey("Error"))
            {
                filterContext.Controller.TempData["Error"] = filterContext.Controller.ViewData.ModelState["Error"];
            }
        }

        base.OnActionExecuted(filterContext);
    }
}

~ / Kontrolörler / MyController.sc:

public class MyController : BaseController
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult Details(int id)
    {
        if (id != 5)
        {
            ModelState.AddModelError("Error", "Specified row does not exist.");
            return RedirectToAction("Error", "Home");
        }
        else
        {
            return View("Specified row exists.");
        }
    }
}

Size başarılı projeler dilerim ;-)


2

Global.cs yazılımını hacklemeden, HandleErrorAttribute ile uğraşmadan, Response.TrySkipIisCustomErrors yapmadan, Application_Error'ı bağlamanıza gerek kalmadan doğru şekilde çalışma hataları alabilirsiniz:

System.web içinde (sadece normal, açık / kapalı)

<customErrors mode="On">
  <error redirect="/error/401" statusCode="401" />
  <error redirect="/error/500" statusCode="500" />
</customErrors>

ve system.webServer içinde

<httpErrors existingResponse="PassThrough" />

Şimdi işler beklendiği gibi davranmalı ve ihtiyacınız olanı görüntülemek için ErrorController'ınızı kullanabilirsiniz.


IIS tarafından atılan bir hata nasıl simüle edilir. 500 veya 504 olsun. ASP.Net MVC - 5 kodu ne yapmak benim özel hata sayfamı test edebilirsiniz IIS istisna benzetmek için
Unbreakable

@Kırılmaz, bir istisna atmak için kodunuzu geçici olarak değiştirin.
theycallmemorty

Benim için bir fark yaratmadı. Bir istisna veya 404 bulunamadı hatası üzerine özel hata sayfama alınmıyorum.
23'te pnizzle

0

Görünüşe göre partiye geç geldim, ama bunu da kontrol etmelisin.

Bu nedenle system.web, uygulama içinde return HttpNotFound () gibi istisnaları önbelleğe almak için

  <system.web>
    <customErrors mode="RemoteOnly">
      <error statusCode="404" redirect="/page-not-found" />
      <error statusCode="500" redirect="/internal-server-error" />
    </customErrors>
  </system.web>

ve system.webServerIIS tarafından yakalanan ve asp.net çerçevesine geçmeyen hataları yakalamak için

 <system.webServer>
    <httpErrors errorMode="DetailedLocalOnly">
      <remove statusCode="404"/>
      <error statusCode="404" path="/page-not-found" responseMode="Redirect"/>
      <remove statusCode="500"/>
      <error statusCode="500" path="/internal-server-error" responseMode="Redirect"/>
  </system.webServer>

Sonuncusunda istemci yanıtı hakkında endişelenirseniz, responseMode="Redirect"bunu değiştirin responseMode="File"ve statik bir html dosyası sunun, çünkü bu 200 yanıt koduna sahip kolay bir sayfa görüntüler.


0

Web.config dosyasına bunu system.webserver etiketi altına aşağıdaki gibi ekleyin,

<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
  <remove statusCode="404"/>
  <remove statusCode="500"/>
  <error statusCode="404" responseMode="ExecuteURL" path="/Error/NotFound"/>
  <error statusCode="500" responseMode="ExecuteURL"path="/Error/ErrorPage"/>
</httpErrors>

ve bir denetleyici ekleyin,

public class ErrorController : Controller
{
    //
    // GET: /Error/
    [GET("/Error/NotFound")]
    public ActionResult NotFound()
    {
        Response.StatusCode = 404;

        return View();
    }

    [GET("/Error/ErrorPage")]
    public ActionResult ErrorPage()
    {
        Response.StatusCode = 500;

        return View();
    }
}

ve saygıdeğer görüşlerini ekleyin, bu kesinlikle işe yarayacak herkes için sanırım.

Ben buldum bu çözüm: Neptün Yüzyıl

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.