Halaman kesalahan khusus di asp.net MVC3

144

Saya sedang mengembangkan situs web MVC3 dan saya mencari solusi untuk menangani kesalahan dan Render Tampilan kustom untuk setiap jenis kesalahan. Jadi bayangkan saya memiliki Pengontrol "Kesalahan" di mana tindakan utamanya adalah "Indeks" (halaman kesalahan umum) dan pengontrol ini akan memiliki beberapa tindakan lebih untuk kesalahan yang mungkin muncul kepada pengguna seperti "Handle500" atau "HandleActionNotFound".

Jadi setiap kesalahan yang mungkin terjadi pada situs web dapat ditangani oleh Pengendali "Kesalahan" ini (contoh: "Pengontrol" atau "Tindakan" tidak ditemukan, 500, 404, dbException, dll).

Saya menggunakan file peta situs untuk menentukan jalur situs web (dan bukan rute).

Pertanyaan ini sudah dijawab, ini adalah balasan untuk Gweebz

Metode applicaiton_error terakhir saya adalah sebagai berikut:

protected void Application_Error() {
//while my project is running in debug mode
if (HttpContext.Current.IsDebuggingEnabled && WebConfigurationManager.AppSettings["EnableCustomErrorPage"].Equals("false"))
{
    Log.Logger.Error("unhandled exception: ", Server.GetLastError());
}
else
{
    try
    {
        var exception = Server.GetLastError();

        Log.Logger.Error("unhandled exception: ", exception);

        Response.Clear();
        Server.ClearError();
        var routeData = new RouteData();
        routeData.Values["controller"] = "Errors";
        routeData.Values["action"] = "General";
        routeData.Values["exception"] = exception;

        IController errorsController = new ErrorsController();
        var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
        errorsController.Execute(rc);
    }
    catch (Exception e)
    {
        //if Error controller failed for same reason, we will display static HTML error page
        Log.Logger.Fatal("failed to display error page, fallback to HTML error: ", e);
        Response.TransmitFile("~/error.html");
    }
}
}
John Louros
sumber
Apa yang harus pengaturan di web.config untuk mendukung ini? Mungkin Anda tidak akan memasukkan pengaturan httperrors?
philbird
forums.asp.net/p/1782402/4894514.aspx/… memiliki beberapa tips bagus seperti IE tidak akan menampilkan halaman kesalahan Anda jika di bawah 512 byte
RickAndMSFT

Jawaban:

201

Berikut adalah contoh cara saya menangani kesalahan khusus. Saya mendefinisikan ErrorsControllertindakan dengan penanganan berbagai kesalahan HTTP:

public class ErrorsController : Controller
{
    public ActionResult General(Exception exception)
    {
        return Content("General failure", "text/plain");
    }

    public ActionResult Http404()
    {
        return Content("Not found", "text/plain");
    }

    public ActionResult Http403()
    {
        return Content("Forbidden", "text/plain");
    }
}

dan kemudian saya berlangganan untuk Application_Errormasuk Global.asaxdan memanggil controller ini:

protected void Application_Error()
{
    var exception = Server.GetLastError();
    var httpException = exception as HttpException;
    Response.Clear();
    Server.ClearError();
    var routeData = new RouteData();
    routeData.Values["controller"] = "Errors";
    routeData.Values["action"] = "General";
    routeData.Values["exception"] = exception;
    Response.StatusCode = 500;
    if (httpException != null)
    {
        Response.StatusCode = httpException.GetHttpCode();
        switch (Response.StatusCode)
        {
            case 403:
                routeData.Values["action"] = "Http403";
                break;
            case 404:
                routeData.Values["action"] = "Http404";
                break;
        }
    }

    IController errorsController = new ErrorsController();
    var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
    errorsController.Execute(rc);
}
Darin Dimitrov
sumber
4
Hanya sedikit catatan. Karena saya ingin merender Tampilan dalam setiap kasus (404, 500, dll.) Pada setiap ActionResult, saya mengembalikan Tampilan. Namun saya mencoba menangkap sekitar konten Application_Error dan saya kasus kegagalan halaman HTML statis dikembalikan. (Saya dapat memposting kode jika seseorang menginginkannya)
John Louros
4
Saya tidak bisa mendapatkan tampilan pisau cukur untuk menggunakan solusi ini di MVC3. return View (model) misalnya hanya mendapat layar kosong.
Extrakun
2
Menambahkan TrySkipIisCustomErrors untuk memperbaikinya untuk IIS7 terintegrasi. Lihat stackoverflow.com/questions/1706934/...
Pavel Savara
1
@ajbeaven, Executeadalah metode yang didefinisikan dalam IControllerantarmuka. Ini tidak mungkin dilindungi. Lihatlah kode saya lebih hati-hati: IController errorsController = new ErrorsController();dan perhatikan jenis errorsControllervariabel yang saya gunakan Executemetode ini. Itu tipe IControllersehingga tidak ada yang mencegah Anda memanggil metode ini. Dan omong-omong Executedilindungi di kelas Controller juga di MVC 3, jadi tidak ada perubahan dalam hal ini.
Darin Dimitrov
2
Diperbaiki dengan secara eksplisit menentukan jenis konten dari respons:Response.ContentType = "text/html";
ajbeaven
6

Anda juga dapat melakukan ini di File Web.Config. Berikut adalah contoh yang berfungsi di IIS 7.5.

     <system.webServer>
          <httpErrors errorMode="DetailedLocalOnly" defaultResponseMode="File">
                <remove statusCode="502" subStatusCode="-1" />
                <remove statusCode="501" subStatusCode="-1" />
                <remove statusCode="412" subStatusCode="-1" />
                <remove statusCode="406" subStatusCode="-1" />
                <remove statusCode="405" subStatusCode="-1" />
                <remove statusCode="404" subStatusCode="-1" />
                <remove statusCode="403" subStatusCode="-1" />
                <remove statusCode="401" subStatusCode="-1" />
                <remove statusCode="500" subStatusCode="-1" />
                <error statusCode="500" path="/notfound.html" responseMode="ExecuteURL" />
                <error statusCode="401" prefixLanguageFilePath="" path="/500.html" responseMode="ExecuteURL" />
                <error statusCode="403" prefixLanguageFilePath="" path="/403.html" responseMode="ExecuteURL" />
                <error statusCode="404" prefixLanguageFilePath="" path="/404.html" responseMode="ExecuteURL" />
                <error statusCode="405" prefixLanguageFilePath="" path="/405.html" responseMode="ExecuteURL" />
                <error statusCode="406" prefixLanguageFilePath="" path="/406.html" responseMode="ExecuteURL" />
                <error statusCode="412" prefixLanguageFilePath="" path="/412.html" responseMode="ExecuteURL" />
                <error statusCode="501" prefixLanguageFilePath="" path="/501.html" responseMode="ExecuteURL" />
                <error statusCode="502" prefixLanguageFilePath="" path="/genericerror.html" responseMode="ExecuteURL" />
           </httpErrors>
</system.webServer>
Brett Allred
sumber
3

Saya melihat Anda menambahkan nilai konfigurasi untuk EnableCustomErrorPagedan Anda juga memeriksa IsDebuggingEnableduntuk menentukan apakah akan menjalankan penanganan kesalahan atau tidak.

Karena sudah ada <customErrors/>konfigurasi di ASP.NET (yang dimaksudkan persis untuk tujuan ini), paling mudah mengatakan:

    protected void Application_Error()
    {
        if (HttpContext.Current == null) 
        {
                // errors in Application_Start will end up here                
        }
        else if (HttpContext.Current.IsCustomErrorEnabled)
        {
                // custom exception handling
        }
    }

Kemudian di konfigurasi Anda akan meletakkan <customErrors mode="RemoteOnly" />mana yang aman untuk digunakan seperti itu, dan ketika Anda perlu menguji halaman kesalahan khusus Anda Anda akan mengaturnya <customErrors mode="On" />sehingga Anda dapat memverifikasi bahwa itu berfungsi.

Catatan Anda juga perlu memeriksa apakah HttpContext.Currentnull karena pengecualian di Application_Startmasih akan menggunakan metode ini meskipun tidak akan ada konteks aktif.

Simon_Weaver
sumber
2

Anda dapat menampilkan halaman kesalahan ramah-pengguna dengan kode status http yang benar dengan menerapkan modul Penanganan Pengecualian Ramah-Pengguna Jeff Atwood dengan sedikit modifikasi untuk kode status http. Ini berfungsi tanpa pengalihan. Meskipun kodenya dari 2004 (!), Ia berfungsi baik dengan MVC. Ini dapat dikonfigurasi sepenuhnya di web.config Anda, tanpa perubahan kode sumber proyek MVC sama sekali.

Modifikasi yang diperlukan untuk mengembalikan status HTTP asli daripada 200status dijelaskan dalam posting forum terkait ini .

Pada dasarnya, di Handler.vb, Anda dapat menambahkan sesuatu seperti:

' In the header...
Private _exHttpEx As HttpException = Nothing

' At the top of Public Sub HandleException(ByVal ex As Exception)...
HttpContext.Current.Response.StatusCode = 500
If TypeOf ex Is HttpException Then
    _exHttpEx = CType(ex, HttpException)
    HttpContext.Current.Response.StatusCode = _exHttpEx.GetHttpCode()
End If
Martin_W
sumber
0

Saya menggunakan MVC 4.5 dan saya mengalami masalah dengan solusi Darin. Catatan: Solusi Darwin sangat bagus dan saya menggunakannya untuk menghasilkan solusi saya. Inilah solusi saya yang dimodifikasi:

protected void Application_Error(object sender, EventArgs e)
{           
var exception = Server.GetLastError();
var httpException = exception as HttpException;
Response.StatusCode = httpException.GetHttpCode();

Response.Clear();
Server.ClearError();


if (httpException != null)
{
    var httpContext = HttpContext.Current;

    httpContext.RewritePath("/Errors/InternalError", false);

    // MVC 3 running on IIS 7+
    if (HttpRuntime.UsingIntegratedPipeline)
    {
        switch (Response.StatusCode)
        {
            case 403:
                httpContext.Server.TransferRequest("/Errors/Http403", true);
                break;
            case 404:
                httpContext.Server.TransferRequest("/Errors/Http404", true);
                break;
            default:
                httpContext.Server.TransferRequest("/Errors/InternalError", true);
                break;
        }
    }
    else
    {
        switch (Response.StatusCode)
        {
            case 403:
                httpContext.RewritePath(string.Format("/Errors/Http403", true));
                break;
            case 404:
                httpContext.RewritePath(string.Format("/Errors/Http404", true));
                break;
            default:
                httpContext.RewritePath(string.Format("/Errors/InternalError", true));
                break;
        }

        IHttpHandler httpHandler = new MvcHttpHandler();
        httpHandler.ProcessRequest(httpContext);
    }
}
}
MVCdragon
sumber
2
Apa masalah Anda dengan solusi Darwin?
Kenny Evitt
Anda tidak menggambarkan masalah yang Anda alami yang memicu jawaban bersaing.
ivanjonas