Апрацоўка памылак і выключэнняў ў ASP.NET MVC

Што такое агульнапрыняты спосаб апрацоўкі памылак і пастак выключэння ў ASP.NET MVC структур? Па агульным меркаванні, мае выключэнне тапырыцца. Так што пласт (View або кантролер) вы б апрацоўваць выключэння (злавіць іх/карыстацкі дысплей дружалюбны тэкст, і г.д.). Я падазраю, што гэта будзе зроблена ў кантролеры? рэдакцыя: <Моцны> Я хацеў бы пазбегнуць паўтарэння той жа код апрацоўкі памылак у кожным кантролеры дзеянні .. таму я шукаю кароткі прыклад таго, як рэалізаваць апрацоўку памылак, не паўтараючы адзін і той жа код.

9
Гэта тое, што я ў канчатковым выніку робіць jQuery Ajax "> stackoverflow.com/questions/8249479/…
дададзена аўтар sarsnake, крыніца
Выкарыстоўваючы метад перахопу можа рэальна дапамагчы тут. А кантэйнеры для ін'екцый шмат залежнасцяў падтрымкі; Я ведаю Spring.NET і замак Віндзор, якія абодва маюць інтэграцыю з ASP.NET MVC. Вы б перахопліваць званкі на кантролерах і апрацоўваць выключэння ў вашым перахопніка.
дададзена аўтар Marijn, крыніца
Гэтае пытанне можа быць добрай адпраўной кропкай: stackoverflow.com/questions/5442231/…
дададзена аўтар Marijn, крыніца

7 адказы

Апрацоўка выключэнняў ў кантролеры можа прывесці да вялікай колькасці паўтаральнага кода. Лепшы падыход апрацоўваць іх у дзеянне фільтра, які пашырае HandleErrorAttribute . Там вы можаце ўвайсці выключэння, а затым перанакіраваць на старонку, якая адлюстроўвае добрае паведамленне, якое паказвае карыстальніку, што нешта пайшло не так.

Тым не менш, ёсць некаторыя выпадкі, калі вам трэба апрацоўваць выключэння ў сваіх метадах кантролера, напрыклад, калі вы можаце акрыяць ад выключэння і паказваць карыстачу адпаведнае паведамленне, напрыклад, выключэнне, якое было кінуць ваш бізнес-пласт, які паказвае, што значэння вы падалі не сапраўдныя. У гэтым выпадку, вы павінны злавіць канкрэтнае выключэнне і паказаць карыстачу тую ж кропку гледжання разам з адпаведным паведамленнем.

<Моцны> EDIT:

public class CustomErrorHandlerAttribute : HandleErrorAttribute
{
     public override void OnException(ExceptionContext filterContext)
     {
         var logger = log4net.LogManager.GetLogger("SomeLoggerHere");

         logger.Error("An unhandled error occurred", filterContext.Exception);

         if (filterContext.HttpContext.Request.IsAjaxRequest())
         {
             filterContext.HttpContext.Response.Clear();
             filterContext.HttpContext.Response.Status = "500 Internal Server Error";
             filterContext.Result = new JsonResult { Data = new { ErrorMessage = filterContext.Exception.Message } };
             filterContext.ExceptionHandled = true;                
         }
         else
         {
             base.OnException(filterContext);
         }

    }

}

EDIT 2: Then you use the attribute like this:

[CustomErrorHandler]
public class AnyController : Controller
{
...
}
15
дададзена
Не маглі б вы даць выразна напісаны прыклад пра тое, як рэалізаваць апрацоўку памылак з выкарыстаннем HandleErrorAttribute? Дзякуй
дададзена аўтар sarsnake, крыніца
Я хацеў бы працягнуць гэтае рашэнне, але я не ясна, дзе вышэй код ідзе? Мой кантролер?
дададзена аўтар sarsnake, крыніца
дзякуй, так што сама CustomErrorHandlerAttribute ідзе куды? той жа файл? гэта мае значэнне?
дададзена аўтар sarsnake, крыніца
дзякуй, мне давядзецца паспрабаваць яго. Я накіроўваю Баунті, як я, хутчэй за ўсё, не будзе часу, каб паспрабаваць яго сёння
дададзена аўтар sarsnake, крыніца
Я дам вам ўзнагароду, я ў канчатковым выніку раблю нешта падобнае, але пашырыць яго для апрацоўкі JsonResult, а таму я магу вярнуць паведамленне пра памылку ў маім ўласным JS код
дададзена аўтар sarsnake, крыніца
Вы можаце анатаваны класы кантролераў з гэтым атрыбутам. Я абнавіў адказ.
дададзена аўтар uvita, крыніца
Вы можаце стварыць іншы клас у іншы дырэкторыі, калі вы хочаце (напрыклад, фільтры)
дададзена аўтар uvita, крыніца

Ваша здагадка дакладная. Вызначана павінен быць кантролер. Вось прыклад:

[HttpPost]
public ActionResult Create(OrderViewModel model)
{
   if (!ModelState.IsValid)
     return View(model);

   try
   {
      repository.Save(model);
      unitOfWork.Commit();
      return RedirectToAction("Index");
   }
   catch (Exception exc)
   {
      _loggingService.Error(exc);
      ModelState.AddModelError("KeyUsedInView", exc.Message);//or, show a generic error.
   }

   return View(model);
}

<Моцнага> Заўвага:

  • Праверце ModelState першым. Калі не дзейнічае, вярнуцца. Атрымаць гэта ўсё з шляху.
  • Не трымайце newing да службы журналявання. Выкарыстоўвайце одноэлементный асобнік, і выкарыстоўваць DI, каб увесці яго ў свае кантралёры так што ваша адпрацоўка інтэрфейсу, напрыклад ILoggingService . Гэта таксама азначае, што вы можаце дадаць іншыя функцыі ў службу рэгістрацыі (па электроннай пошце падтрымкі, напрыклад).
  • Вашы ніжнія пласты (паслугі, сховішча і г.д.) могуць прывесці памылкі (карыстацкі або убудаваны), так што гэта важна кантролер ловіць іх, так як гэта «агрэгатар" і што адказвае для патоку дадзеных паміж кліентам і серверам.
  • Выкарыстоўвайце ModelState.AddModelError , каб дадаць памылкі, так што View можа паказаць іх. Вы таксама можаце выкарыстоўваць карыстацкія выключэння, якія могуць быць дружалюбным да карыстача, і вы паказаць іх карыстальніку. Для памылак ніжняга ўзроўню (SQL, і г.д.), вы можаце проста дадаць агульную памылку ў ModelState ( «На жаль, адбылася памылка. Калі ласка, паспрабуйце яшчэ раз пазней»).
3
дададзена
@ Amir978 - я не разумею. Дзе ён прасіць, каб зрабіць гэтыя рэчы ў гэтым пытанні?
дададзена аўтар RPM1984, крыніца
@ Amir978 - няма Probs. Не ведаю, чаму вы «захаваць імя» будзе - які сцэнар? Зарэгістравацца? Можа апублікаваць яшчэ адно пытанне. Што тычыцца справаздачы пра памылку - гэта тое, што Elmah для. І вы можаце выкарыстоўваць нешта накшталт Варта, каб захапіць памылкі пратакалявання.
дададзена аўтар RPM1984, крыніца
Я палічыў за лепшае б не паўтарыць той жа код у кожным дзеянні.
дададзена аўтар sarsnake, крыніца
Як вы можаце захаваць імя карыстальніка ў гэтым выпадку? І як стварыць справаздачу аб усіх памылках, якія адбыліся?
дададзена аўтар Amir978, крыніца
Вы прама .I've проста папрасіў, каб знайсці рашэнне для сябе.
дададзена аўтар Amir978, крыніца

Гэта не так проста, як гэта можа здацца.

Калі вам патрэбна цэнтралізаваная апрацоўка выключэнняў, самы хуткі спосаб, каб перавызначыць метад OnException ў кантролеры

[NonAction]
        protected override void OnException(ExceptionContext filterContext)
        {

            this.Session["ErrorException"] = filterContext.Exception;

            if (filterContext.Exception.GetType() == typeof(PEDException))
            {
               //Mark exception as handled
                filterContext.ExceptionHandled = true;

               //... logging, etc

               //Redirect
                filterContext.Result = this.RedirectToAction( "ShowError", "Errors");
            }

            base.OnException(filterContext);
        }

Як вы можаце бачыць у гэтым метадзе я злавіла ўсе неапрацаваныя выключэння PEDException, калі ў вас ёсць карыстацкія выключэння, згенераваныя з вашых бл, я думаю, маючы базавы кантролер з метадам OnException можа быць добрым рашэннем, аднак ёсць выпадкі, калі гэта можа патэнцыйна быць небяспечным. Наогул-то я думаю, што гэта лепш, каб вызначыць прыстасаваныя атрыбуты (Падаўжэнне ErrorAttributeFilter), каб пазбегнуць шматлікіх іншых праблем (з кэшаваннем, напрыклад, вашы дзеянні проста не будзе выконвацца на ўсіх, у той час як атрыбут заўсёды будзе выконвацца).

Калі ласка, азнаёмцеся з раздзелам тут далейшай інфармацыі

2
дададзена

Вы можаце стварыць уласны базавы кантролер і успадкаваць ад базавага класа кантролера. Затым перавызначыць OnException ў вашым customcontroller. Тады ў кожнага з ўспадкаваць кантролера з новай карыстацкай базы controlller.

У якасці альтэрнатывы, вы можаце перавызначыць падзея Application_Error ў global.asax

1
дададзена

Гэта сапраўды залежыць ад таго, што вы імкнецеся дасягнуць.

Для простага сцэнара адлюстравання карыстацкага паведамленні аб любых памылках ўсё вакол, вы можаце выкарыстоўваць старую добрую канфігурацыю карыстацкіх памылак у вашым web.config.

Звярніце ўвагу, што гэта будзе выкарыстоўвацца на памылкі, якія нават не дабрацца да кропкі дасягнення кантролераў. Напрыклад, калі ёсць праблемы з не належным чынам закадаваныя адмысловымі значэннямі ў URL.

Атрыбут HandleError, ці ваш уласны атрыбут звычаю, дазволіць вам кантраляваць танчэй, што вы хочаце, хочаце ў іншых сцэнарах.

Звярніце ўвагу, што калі вы хочаце ўжыць карыстацкі дэскрыптар атрыбут памылкі на ўсе кантралёры, вы можаце зрабіць гэта, ужываючы яго ў якасці глабальнага фільтра дзеянняў. Такім чынам, вам не трэба відавочна прымяніць яго да кожнага і кожнаму кантролеру.

0
дададзена

Я звычайна больш прыярытэтнае Application_Error ў файле Global.asax і перанакіраваньні карыстальніка на агульную старонку выключэнні для кожнага выключэння, а затым адправіць па электроннай пошце з некаторымі дэталямі. Дастаткова проста. Вось што я звычайна выкарыстоўваю:

protected void Application_Error(object sender, EventArgs e)
{
    if (Request.Url.ToString().StartsWith("http://localhost:"))
        return;
    string msg;
    Exception ex = Server.GetLastError().GetBaseException();
    StringBuilder sb = new StringBuilder();
    sb.AppendLine("Exception Found");
    sb.AppendLine("Timestamp: " + System.DateTime.Now.ToString());
    sb.AppendLine("Error in: " + Request.Url.ToString());
    sb.AppendLine("Browser Version: " + Request.UserAgent.ToString());
    sb.AppendLine("User IP: " + Request.UserHostAddress.ToString());
    sb.AppendLine("Error Message: " + ex.Message);
    sb.AppendLine("Stack Trace: " + ex.StackTrace);
    msg = sb.ToString();
    Server.ClearError();
    YourMailHelper.SendException("Your Site Exception", msg);
    Response.Redirect("~/Error.html");
}
0
дададзена

Хоць я згодны, што вядзенне часопіса выключэнняў аперацыі павінны быць цэнтралізаваныя на ўзроўні кантролера АСНОВЫ дзеля паслядоўнасці ... Я таксама лічу, што стандартны спосаб адлюстравання карыстацкіх паведамленняў пра памылкі ў інтэрфейсе павінна быць разгледжана ў дадатку да патрабаванняў рэгістрацыі. Выключэння былі злоўленыя і рэгіструюцца на ўзроўні кантролера затым можа быць абгорнуты ў «дружалюбных Exception» і перадаецца ў цэнтральны працэсар выключэнняў. Файл error.cshtml ў агульнай папцы прагляду з'яўляецца добрым месцам для апрацоўкі і адлюстравання «дружалюбных Exception», які аблягае «Фактычнае выключэнне», якое адбылося, і быў зарэгістравана на ўзроўні кантролера і перадаецца ў error.cshtml.

Я выкарыстоўваю карыстацкія базы кіравання і налады HandleErrorAttribute з выкарыстаннем метаду RegisterGolbalFilters у класе FilterConfig выкліканым з падзеі Global.asax Application_Start

Base_Controller код

public class Base_Controller : Controller
{
    protected override void OnException(ExceptionContext filterContext)
    {
        Exception e = filterContext.Exception;
        //Custom Exception Logging Here
        //Log Exception e
        //Elmah.Mvc.ElmahController ec = new Elmah.Mvc.ElmahController();
        base.OnException(filterContext);
    }
}

FilterConfig.cs код

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    }
}

Global.asax Application_Start код

void Application_Start(object sender, EventArgs e)
{
   //Code that runs on application startup
    AreaRegistration.RegisterAllAreas();
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

}

Гэтая частка з'яўляецца даволі стандартным ... Гэта тое, што рабіць далей, што сапраўды мае значэнне для карыстальніка. Я выкарыстоўваю клас errorhandling для апрацоўкі выключэнняў цэнтралізавана і адлюстроўваць «дружалюбныя» кантэкст на аснове паведамленняў карыстача на аснове кантролера і дзеяннях, якое выклікала выключэнне. У прыкладзе кода ніжэй я перамясціў злавіць блок на старонцы error.cshtml ў Views/агульнай тэчцы, каб захаваць яго простым. Код ніжэй проста прыклад код, як паведамленне пра памылку дружнага будзе мяняцца ў залежнасці ад кантэксту прыкладання, і вы можаце перамясціць апрацоўку выключэнняў у клас для абслугоўвання.

//Check for Transport Exception with "Actual Exception" stored
//in the inner exception property
if (Model.Exception.InnerException != null)
{
    errFriendly = Model.Exception.Message;
    modelEx = Model.Exception.InnerException;
}
else
{
    modelEx = Model.Exception;
}
try
{           
    throw modelEx; 
}
catch (System.Data.SqlClient.SqlException ex)
{
    //Display Landing page friendly error for exception caused by home controller
    //Display generic data access error for all other controllers/actions
    if (Model.ActionName == "Index" && Model.ControllerName == "Home")
    {errFriendly = "Landing page cannot display product data...";}
    else
    {errFriendly = "Problem Accessing Data...";}
    errType = ex.GetType().ToString();
    errActual = ex.Message;
}

To download the entire code sample see the blog post at: http://www.prodataman.com/Blog/Post/119/MVC-Custom-Exception-Handling

0
дададзена