मैं ASP.NET MVC में 404 को कैसे ठीक से संभाल सकता हूं?


432

मैं RC2 का उपयोग कर रहा हूं

URL रूटिंग का उपयोग करना:

routes.MapRoute(
    "Error",
     "{*url}",
     new { controller = "Errors", action = "NotFound" }  // 404s
);

उपरोक्त इस तरह के अनुरोधों का ध्यान रखता है (प्रारंभिक MVC प्रोजेक्ट द्वारा डिफ़ॉल्ट रूट टेबल सेटअप मानते हुए): "/ blah / blah / blah / blah"

नियंत्रक में ही हैंडलडेनगेंशन () को ओवरराइड करना:

// 404s - handle here (bad action requested
protected override void HandleUnknownAction(string actionName) {
    ViewData["actionName"] = actionName;
    View("NotFound").ExecuteResult(this.ControllerContext);
}  

हालाँकि पिछली रणनीतियाँ खराब / अज्ञात नियंत्रक के अनुरोध को नहीं संभालती हैं। उदाहरण के लिए, मेरे पास "/ IDoNotExist" नहीं है, अगर मैं यह अनुरोध करता हूं कि मुझे वेब सर्वर से जेनेरिक 404 पेज मिलें और मेरे 404 नहीं तो रूटिंग + ओवरराइड का उपयोग करें।

तो आखिरकार, मेरा प्रश्न यह है कि क्या एमवीसी ढांचे में किसी मार्ग या किसी अन्य चीज़ का उपयोग करके इस प्रकार के अनुरोध को पकड़ने का कोई तरीका है?

या क्या मुझे केवल अपने 404 हैंडलर के रूप में Web.Config customErrors का उपयोग करने के लिए डिफ़ॉल्ट होना चाहिए और यह सब भूल जाना चाहिए? मुझे लगता है कि अगर मैं customErrors के साथ जाता हूं, तो मुझे सीधे / एक्सेस पर Web.Config प्रतिबंधों के कारण सामान्य 404 पृष्ठ / दृश्य के बाहर स्टोर करना होगा।


3
यह 404 त्रुटि है, मैं इसके बारे में परेशान नहीं करूंगा। इसे 404 प्रदर्शित करें। निश्चित रूप से उपयोगकर्ता ने कुछ गलत किया है। या यदि यह कुछ ऐसा है जिसे स्थानांतरित किया गया है, तो आपके आवेदन को उस अनुरोध को लेना चाहिए और स्थायी रूप से पुनर्निर्देशित करना चाहिए। 404 वेबसर्वर से संबंधित नहीं है। आप हमेशा त्रुटि के लिए iis पृष्ठों को अनुकूलित कर सकते हैं।
मामू

आप इस समाधान पर एक नज़र डाल सकते हैं। साथ ही blog.dantup.com/2009/04/…
डेवलपर

ben.onfabrik.com/posts/aspnet-mvc-custom-error-pages में भी कुछ अच्छी जानकारी है
क्रिस एस

4
यह शर्म की बात है कि 4 स्थिर बाद में और 5 से अधिक वर्षों से जारी है, asp.net MVC + IIS में 404 से निपटने की स्थिति में वास्तव में सुधार नहीं हुआ है और यह अभी भी क्यू एंड ए पर जाना है कि इसे कैसे संभालना है।
जोएलमदेव

जवाबों:


271

कोड http://blogs.microsoft.co.il/blogs/shay/archive-2009/03/06/real-world-error-hadnling-in-asp-net-mvc-rc2.aspx और कार्यों से लिया गया है ASP.net MVC 1.0 में भी

यहां बताया गया है कि मैं http अपवादों को कैसे संभालता हूं:

protected void Application_Error(object sender, EventArgs e)
{
   Exception exception = Server.GetLastError();
   // Log the exception.

   ILogger logger = Container.Resolve<ILogger>();
   logger.Error(exception);

   Response.Clear();

   HttpException httpException = exception as HttpException;

   RouteData routeData = new RouteData();
   routeData.Values.Add("controller", "Error");

   if (httpException == null)
   {
       routeData.Values.Add("action", "Index");
   }
   else //It's an Http Exception, Let's handle it.
   {
       switch (httpException.GetHttpCode())
       {
          case 404:
              // Page not found.
              routeData.Values.Add("action", "HttpError404");
              break;
          case 500:
              // Server error.
              routeData.Values.Add("action", "HttpError500");
              break;

           // Here you can handle Views to other error codes.
           // I choose a General error template  
           default:
              routeData.Values.Add("action", "General");
              break;
      }
  }           

  // Pass exception details to the target error View.
  routeData.Values.Add("error", exception);

  // Clear the error on server.
  Server.ClearError();

  // Avoid IIS7 getting in the middle
  Response.TrySkipIisCustomErrors = true; 

  // Call target Controller and pass the routeData.
  IController errorController = new ErrorController();
  errorController.Execute(new RequestContext(    
       new HttpContextWrapper(Context), routeData));
}

23
अद्यतन: http 404 की जाँच करना निश्चित रूप से आवश्यक है, लेकिन मुझे अभी भी पूरा यकीन नहीं है कि आपको कभी 500 मिलेंगे। आपको रिस्पांस सेट करने की भी आवश्यकता है। साइटसकोड = 404 या 500 अन्यथा Google इन पृष्ठों को अनुक्रमित करना शुरू कर देगा। यदि आप एक 200 स्टेटस कोड वापस कर रहे हैं जो यह कोड वर्तमान में करता है
शमौन_वेवर

6
@Simon_Weaver: सहमत! इसके लिए 404 स्टेटस कोड वापस करने होंगे। यह अनिवार्य रूप से 404 समाधान के रूप में टूट जाता है जब तक कि यह नहीं करता है। इसे देखें: कोडिंगहोरर
मैट

1
इस पूरे सुझाव के साथ एक अंतर्निहित दोष है - जब तक निष्पादन Global.asax तक बुदबुदाया, तब तक HttpContext का बहुत अधिक हिस्सा गायब है। आप अपने नियंत्रकों में वापस नहीं भेज सकते हैं जैसे कि उदाहरण से पता चलता है। शीर्ष पर ब्लॉग लिंक में टिप्पणियों का संदर्भ लें।
मैट कोकाज

3
जैसा कि ऊपर से कुछ टिप्पणियों और लिंक किए गए पोस्ट का उल्लेख है, यह काम नहीं करता है। त्रुटि-नियंत्रण हिट है, लेकिन एक रिक्त स्क्रीन देता है। (mvc 3 का उपयोग करते हुए)
रयानडब्ल्यू

4
कुछ सही नहीं लगता है, MVC का पूरा उद्देश्य यह है कि अमूर्तता को दूर करना और फिर भी यह फिर से है ...
एलेक्स नोल्को

255

404 के लिए आवश्यकताएँ

404 समाधान के लिए निम्नलिखित मेरी आवश्यकताएं हैं और नीचे मैं दिखाता हूं कि मैं इसे कैसे लागू करता हूं:

  • मैं खराब कार्यों के साथ मिलान वाले मार्गों को संभालना चाहता हूं
  • मैं खराब नियंत्रकों के साथ मिलान किए गए मार्गों को संभालना चाहता हूं
  • मैं बिना मिलान वाले मार्गों को संभालना चाहता हूं (मनमाने ढंग से यूआरएल जो मेरा ऐप समझ नहीं सकता है) - मैं नहीं चाहता कि ये Global.asax या IIS तक बुदबुदाएं क्योंकि तब मैं अपने MVC ऐप में ठीक से रीडायरेक्ट नहीं कर सकता
  • मैं ऊपर के रूप में उसी तरह से हैंडल करना चाहता हूं, कस्टम 404s - जैसे जब किसी ऑब्जेक्ट के लिए एक आईडी प्रस्तुत की जाती है जो मौजूद नहीं है (शायद हटाए गए)
  • मैं चाहता हूं कि मेरे सभी 404s एक एमवीसी दृश्य (एक स्थिर पृष्ठ नहीं) पर लौटें, जिसके लिए मैं बाद में अधिक डेटा पंप कर सकता हूं यदि आवश्यक हो ( अच्छा 404 डिजाइन ) और उन्हें HTTP 404 स्थिति कोड वापस करना होगा

समाधान

मुझे लगता है कि आपको Application_Errorवैश्विक चीजों में बचत करनी चाहिए। उच्चतर चीजों के लिए, जैसे कि बिना किसी अपवाद के और लॉगिंग (जैसे कि शाय जेकोबी के जवाब शो) लेकिन 404 हैंडलिंग नहीं। यही कारण है कि मेरा सुझाव 40. सामान को Global.asax फ़ाइल से बाहर रखता है।

चरण 1: 404-त्रुटि तर्क के लिए एक सामान्य स्थान है

यह स्थिरता के लिए एक अच्छा विचार है। एक ErrorController का उपयोग करें ताकि आपके सुव्यवस्थित 404 पृष्ठ के भविष्य में सुधार आसानी से अनुकूलित हो सके। इसके अलावा, सुनिश्चित करें कि आपकी प्रतिक्रिया में 404 कोड है !

public class ErrorController : MyController
{
    #region Http404

    public ActionResult Http404(string url)
    {
        Response.StatusCode = (int)HttpStatusCode.NotFound;
        var model = new NotFoundViewModel();
        // If the url is relative ('NotFound' route) then replace with Requested path
        model.RequestedUrl = Request.Url.OriginalString.Contains(url) & Request.Url.OriginalString != url ?
            Request.Url.OriginalString : url;
        // Dont get the user stuck in a 'retry loop' by
        // allowing the Referrer to be the same as the Request
        model.ReferrerUrl = Request.UrlReferrer != null &&
            Request.UrlReferrer.OriginalString != model.RequestedUrl ?
            Request.UrlReferrer.OriginalString : null;

        // TODO: insert ILogger here

        return View("NotFound", model);
    }
    public class NotFoundViewModel
    {
        public string RequestedUrl { get; set; }
        public string ReferrerUrl { get; set; }
    }

    #endregion
}

चरण 2: एक आधार नियंत्रक वर्ग का उपयोग करें ताकि आप आसानी से अपने कस्टम 404 कार्रवाई और वायर अप कर सकें HandleUnknownAction

ASP.NET MVC में 404 स्थानों पर कई स्थानों पर पकड़े जाने की आवश्यकता है। पहला है HandleUnknownAction

यह InvokeHttp404विधि ErrorControllerहमारी नई Http404कार्रवाई को फिर से रूट करने के लिए एक आम जगह बनाती है । DRY सोचो !

public abstract class MyController : Controller
{
    #region Http404 handling

    protected override void HandleUnknownAction(string actionName)
    {
        // If controller is ErrorController dont 'nest' exceptions
        if (this.GetType() != typeof(ErrorController))
            this.InvokeHttp404(HttpContext);
    }

    public ActionResult InvokeHttp404(HttpContextBase httpContext)
    {
        IController errorController = ObjectFactory.GetInstance<ErrorController>();
        var errorRoute = new RouteData();
        errorRoute.Values.Add("controller", "Error");
        errorRoute.Values.Add("action", "Http404");
        errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
        errorController.Execute(new RequestContext(
             httpContext, errorRoute));

        return new EmptyResult();
    }

    #endregion
}

चरण 3: अपने नियंत्रक कारखाने में निर्भरता इंजेक्शन का उपयोग करें और 404 HttpException को तार दें

जैसे (यह संरचना नहीं है)

MVC1.0 उदाहरण:

public class StructureMapControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(Type controllerType)
    {
        try
        {
            if (controllerType == null)
                return base.GetControllerInstance(controllerType);
        }
        catch (HttpException ex)
        {
            if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound)
            {
                IController errorController = ObjectFactory.GetInstance<ErrorController>();
                ((ErrorController)errorController).InvokeHttp404(RequestContext.HttpContext);

                return errorController;
            }
            else
                throw ex;
        }

        return ObjectFactory.GetInstance(controllerType) as Controller;
    }
}

MVC2.0 उदाहरण:

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        try
        {
            if (controllerType == null)
                return base.GetControllerInstance(requestContext, controllerType);
        }
        catch (HttpException ex)
        {
            if (ex.GetHttpCode() == 404)
            {
                IController errorController = ObjectFactory.GetInstance<ErrorController>();
                ((ErrorController)errorController).InvokeHttp404(requestContext.HttpContext);

                return errorController;
            }
            else
                throw ex;
        }

        return ObjectFactory.GetInstance(controllerType) as Controller;
    }

मुझे लगता है कि त्रुटियों को पकड़ने के लिए यह बेहतर है कि वे कहाँ उत्पन्न होते हैं। यही कारण है कि मैं ऊपर से Application_Errorहैंडलर को पसंद करता हूं ।

404s को पकड़ने के लिए यह दूसरा स्थान है।

चरण 4: यूआरएल के लिए Global.asax में एक NotFound मार्ग जोड़ें जो आपके ऐप में पार्स होने में विफल हो

यह मार्ग हमारी Http404कार्रवाई की ओर इशारा करता है। ध्यान दें कि urlपरम एक रिश्तेदार url होगा क्योंकि रूटिंग इंजन यहाँ डोमेन भाग को हटा रहा है? यही कारण है कि हमारे पास चरण 1 में सशर्त उर तर्क है।

        routes.MapRoute("NotFound", "{*url}", 
            new { controller = "Error", action = "Http404" });

यह एक MVC ऐप में 404s को पकड़ने के लिए तीसरा और अंतिम स्थान है जिसे आप खुद नहीं लेते हैं। यदि आप यहां बेजोड़ मार्गों को नहीं पकड़ते हैं तो MVC ASP.NET (Global.asax) तक की समस्या को पारित कर देगा और आप वास्तव में इस स्थिति में नहीं चाहते हैं।

चरण 5: अंत में, 404s को तब लगाएं जब आपका ऐप कुछ नहीं पा सकता है

जैसे कि जब एक खराब आईडी मेरे ऋण नियंत्रक को प्रस्तुत की जाती है (तब प्राप्त होती है MyController):

    //
    // GET: /Detail/ID

    public ActionResult Detail(int ID)
    {
        Loan loan = this._svc.GetLoans().WithID(ID);
        if (loan == null)
            return this.InvokeHttp404(HttpContext);
        else
            return View(loan);
    }

यह अच्छा होगा यदि यह सब कम कोड वाले कम स्थानों पर झुका जा सकता है लेकिन मुझे लगता है कि यह समाधान अधिक बनाए रखने योग्य, अधिक परीक्षण योग्य और काफी व्यावहारिक है।

अब तक की प्रतिक्रिया के लिए धन्यवाद। मुझे और अधिक प्राप्त करना अच्छा लगेगा।

नोट: यह मेरे मूल उत्तर से महत्वपूर्ण रूप से संपादित किया गया है, लेकिन उद्देश्य / आवश्यकताएं समान हैं - यही कारण है कि मैंने एक नया उत्तर नहीं जोड़ा है


12
पूरा लिखने के लिए धन्यवाद। एक अतिरिक्त यह है कि जब IIS7 के तहत चल रहा है, तो आपको "ट्रूस्किपिसिसकस्टमर्रर" संपत्ति को सही पर सेट करने की आवश्यकता है। अन्यथा IIS अभी भी डिफ़ॉल्ट 404 पृष्ठ लौटाएगा। हमने Response.TrySkipIiisCustomErrors = true जोड़ा; चरण 5 में लाइन के बाद जो स्थिति कोड सेट करता है। msdn.microsoft.com/en-us/library/…
रिक

1
@Ryan customErrorsweb.config का खंड स्थिर रीडायरेक्ट पृष्ठों को परिभाषित करता है, जो IIS नहीं तो उच्च स्तर पर हैंडल किए जाते हैं। यह वह नहीं है जो मुझे चाहिए था क्योंकि मुझे एमवीसी व्यूज का परिणाम चाहिए (इसलिए मैं उनमें डेटा आदि रख सकता हूं)। मैं स्पष्ट रूप से यह नहीं कहूंगा कि " customErrorsMVC में अप्रचलित है" लेकिन मेरे लिए और यह 404 समाधान वे निश्चित रूप से हैं।
मैट कोकाज

1
इसके अलावा, क्या कोई स्टेप 3 को अपडेट कर सकता है ताकि स्ट्रक्चुरेप का इस्तेमाल न हो? हो सकता है कि अगर आप पहले से ही एक नियंत्रक का उपयोग नहीं कर रहे हैं, तो बस एक सामान्य नियंत्रककार्यक्रम को लागू करना आसान होगा।
डेविड मर्डोक

7
यह MVC3 के लिए ठीक काम करता है। मैंने ObjectFactory.GetInstanceMVC3 की DependencyResolver.Current.GetServiceजगह स्विच किया, इसलिए यह अधिक सामान्य है। मैं Ninject का उपयोग कर रहा हूँ।
कामरानिकस

122
क्या किसी और को यह समझदारी से पागल लगती है कि वेब फ्रेमवर्क में 404 जैसी सामान्य बात इतनी जटिल है।
क्वेंटिन-स्टारिन

235

ASP.NET MVC कस्टम 404 पृष्ठों को बहुत अच्छी तरह से समर्थन नहीं करता है। कस्टम नियंत्रक कारखाना, कैच-ऑल रूट, बेस कंट्रोलर क्लास के साथ HandleUnknownAction- argh!

IIS कस्टम त्रुटि पृष्ठ अब तक बेहतर विकल्प हैं:

web.config

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

ErrorController

public class ErrorController : Controller
{
    public ActionResult PageNotFound()
    {
        Response.StatusCode = 404;
        return View();
    }
}

नमूना परियोजना


38
यह स्वीकार किया गया है कि जब तक स्वीकार किए जाते हैं !!! ASP.NET MVC 3 पर IIS एक्सप्रेस के साथ उत्कृष्ट कार्य करता है।
आंद्रेई रोनेया

7
यदि आप IIS7 + का उपयोग कर रहे हैं तो यह निश्चित रूप से जाने का रास्ता है। +1!
elo80ka

3
क्या यह संभव है कि जब आप उसी स्थिति में JSON में काम कर रहे हों तो केवल 404 का स्टेटस लौटा सकते हैं?
विन्नी

6
यह आईआईएस एक्सप्रेस में बहुत अच्छा काम कर रहा है, लेकिन जैसे ही मैं साइट को उत्पादन में 7.5 आईआईएस 7.5 में तैनात करता हूं, सभी मुझे मिलता है त्रुटि के बजाय एक सफेद पृष्ठ है।
मोल

2
मेरे परीक्षणों के अनुसार (MVC3 के साथ) यह कार्यात्मक होने के customErrors mode="On"साथ-साथ टूट जाता है HandleErrorAttribute। नियंत्रक क्रियाओं में बिना किसी अपवाद के कस्टम त्रुटि पृष्ठ अब नहीं परोसे जाते हैं।
सलुमा

153

त्वरित उत्तर / टीएल; डीआर

यहां छवि विवरण दर्ज करें

आलसी लोगों के लिए:

Install-Package MagicalUnicornMvcErrorToolkit -Version 1.0

फिर इस लाइन को हटा दें global.asax

GlobalFilters.Filters.Add(new HandleErrorAttribute());

और यह केवल IIS7 + और IIS एक्सप्रेस के लिए है।

यदि आप कैसिनी का उपयोग कर रहे हैं .. अच्छी तरह से .. उम .. एर .. अजीब ... भद्दा


लंबा, समझाया गया उत्तर

मुझे पता है कि यह उत्तर दिया गया है। लेकिन जवाब वास्तव में सरल है (वास्तव में इसका जवाब देने के लिए डेविड फाउलर और डेमियन एडवर्ड्स के लिए खुश हैं)।

नहीं है कुछ भी कस्टम करने की कोई आवश्यकता

के लिए ASP.NET MVC3, सभी बिट्स और टुकड़े हैं।

चरण 1 -> TWO स्पॉट में अपने web.config को अपडेट करें।

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

तथा

<system.webServer>
    <httpErrors errorMode="Custom">
      <remove statusCode="404" subStatusCode="-1" />
      <error statusCode="404" path="/NotFound" responseMode="ExecuteURL" />
      <remove statusCode="500" subStatusCode="-1" />
      <error statusCode="500" path="/ServerError" responseMode="ExecuteURL" />
    </httpErrors>    

...
<system.webServer>
...
</system.web>

अब मैंने जिन ROUTES का उपयोग करने का निर्णय लिया है, उन पर ध्यान दें। आप कुछ भी उपयोग कर सकते हैं, लेकिन मेरे मार्ग हैं

  • /NotFound <- 404 नहीं मिला, त्रुटि पृष्ठ।
  • /ServerError<- किसी अन्य त्रुटि के लिए, मेरे कोड में होने वाली त्रुटियां शामिल करें। यह एक 500 आंतरिक सर्वर त्रुटि है

देखें कि <system.web>केवल एक कस्टम प्रविष्टि में पहले खंड में कैसे है ? statusCode="404"प्रवेश? मैंने केवल एक स्थिति कोड सूचीबद्ध किया है, क्योंकि 500 Server Error(यानी उन pesky त्रुटि जो आपके कोड में बग होने पर और उपयोगकर्ता के अनुरोध को क्रैश करता है) सहित अन्य सभी त्रुटियां होती हैं .. अन्य सभी त्रुटियां सेटिंग द्वारा नियंत्रित की जाती हैं defaultRedirect="/ServerError".. जो कहती है , यदि आप 404 पृष्ठ नहीं हैं, तो कृपया मार्ग नहीं मिला /ServerError

ठीक है। उस रास्ते से बाहर है .. अब मेरे मार्गों में सूचीबद्ध हैglobal.asax

चरण 2 - Global.asax में मार्गों का निर्माण

यहाँ मेरा पूरा मार्ग खंड है ..

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    routes.IgnoreRoute("{*favicon}", new {favicon = @"(.*/)?favicon.ico(/.*)?"});

    routes.MapRoute(
        "Error - 404",
        "NotFound",
        new { controller = "Error", action = "NotFound" }
        );

    routes.MapRoute(
        "Error - 500",
        "ServerError",
        new { controller = "Error", action = "ServerError"}
        );

    routes.MapRoute(
        "Default", // Route name
        "{controller}/{action}/{id}", // URL with parameters
        new {controller = "Home", action = "Index", id = UrlParameter.Optional}
        );
}

वह दो अनदेखी मार्गों को सूचीबद्ध करता है -> axd'sऔर favicons(ooo! बोनस अनदेखी मार्ग, आपके लिए!) तब (और आदेश महत्वपूर्ण है), मेरे पास मेरे दो स्पष्ट त्रुटि हैंडलिंग मार्ग हैं .. इसके बाद किसी भी अन्य मार्ग हैं। इस मामले में, डिफ़ॉल्ट एक। बेशक, मेरे पास अधिक है, लेकिन यह मेरी वेब साइट के लिए विशेष है। बस सुनिश्चित करें कि त्रुटि मार्ग सूची के शीर्ष पर हैं। आदेश अनिवार्य है

अंत में, जब हम अपनी global.asaxफ़ाइल के अंदर होते हैं , तो हम विश्व स्तर पर HandleError विशेषता को पंजीकृत नहीं करते हैं। नहीं, नहीं, नहीं सर। नड्डा। नहीं। निएन। नकारात्मक। Noooooooooo ...

इस लाइन को हटा दें global.asax

GlobalFilters.Filters.Add(new HandleErrorAttribute());

चरण 3 - कार्रवाई विधियों के साथ नियंत्रक बनाएं

अब .. हम दो क्रिया विधियों के साथ एक नियंत्रक जोड़ते हैं ...

public class ErrorController : Controller
{
    public ActionResult NotFound()
    {
        Response.StatusCode = (int)HttpStatusCode.NotFound;
        return View();
    }

    public ActionResult ServerError()
    {
        Response.StatusCode = (int)HttpStatusCode.InternalServerError;

        // Todo: Pass the exception into the view model, which you can make.
        //       That's an exercise, dear reader, for -you-.
        //       In case u want to pass it to the view, if you're admin, etc.
        // if (User.IsAdmin) // <-- I just made that up :) U get the idea...
        // {
        //     var exception = Server.GetLastError();
        //     // etc..
        // }

        return View();
    }

    // Shhh .. secret test method .. ooOOooOooOOOooohhhhhhhh
    public ActionResult ThrowError()
    {
        throw new NotImplementedException("Pew ^ Pew");
    }
}

ठीक है, इसकी जाँच करें। सबसे पहले, यहाँ कोई [HandleError] विशेषता नहीं है। क्यों? क्योंकि ASP.NETफ्रेमवर्क में निर्मित पहले से ही त्रुटियों को संभाल रहा है और हमने एक त्रुटि को संभालने के लिए हमें जो कुछ भी करने की आवश्यकता है उसे निर्दिष्ट किया है :) यह इस पद्धति में है!

इसके बाद, मेरे पास दो कार्य विधियाँ हैं। वहां कुछ भी कठिन नहीं है। यदि आप कोई अपवाद जानकारी दिखाना चाहते हैं, तो Server.GetLastError()आप उस जानकारी को प्राप्त करने के लिए उपयोग कर सकते हैं ।

बोनस डब्ल्यूटीएफ: हां, मैंने एक तीसरा एक्शन तरीका बनाया, त्रुटि से निपटने के लिए।

चरण 4 - दृश्य बनाएं

और अंत में, दो दृश्य बनाएं। इस नियंत्रक के लिए, उन्हें सामान्य दृश्य स्थान पर रखें।

यहां छवि विवरण दर्ज करें

बोनस टिप्पणी

  • आप एक की जरूरत नहीं है Application_Error(object sender, EventArgs e)
  • उपरोक्त सभी चरण एल्माह के साथ पूरी तरह से 100% काम करते हैं । एल्मा फ्रैकिंग विक्स!

और वह, मेरे दोस्त, यह होना चाहिए।

अब, इसे पढ़ने के लिए बधाई और पुरस्कार के रूप में एक गेंडा है!

यहां छवि विवरण दर्ज करें


इसलिए मैंने इसे लागू करने की कोशिश की, लेकिन कुछ समस्याएँ ... पहली, आपको weeb.config में पथ से पहले एक ~ की आवश्यकता है या यह वर्चुअल निर्देशिकाओं के लिए काम नहीं करता है। 2-यदि IIS कस्टम त्रुटियां आग उगलती हैं और दृश्य एक लेआउट का उपयोग कर रहा है जो बिल्कुल भी प्रस्तुत नहीं करता है, तो बस एक सफेद पृष्ठ। मैंने उस लाइन को कंट्रोलर में जोड़कर हल किया "Response.TrySkipIisCustomErrors = true;" । हालाँकि, यह तब भी काम नहीं करता है जब आप एक यूआरएल पर जाते हैं जो एक फ़ाइल है, लेकिन 404 .. जैसे mysite / जो भी / fake.html एक सफेद पृष्ठ मिलता है।
राबर्ट नैक

3
-1, क्षमा करें, मेरे लिए 404 के लिए url को बदलने वाला कोई भी समाधान गलत है। और Webconfig के साथ MVC में कोई तरीका नहीं है कि आप इसे url को बदले बिना संभाल सकते हैं, या आपको इसे करने में सक्षम होने के लिए स्थैतिक html फ़ाइलें या aspx (हाँ, सादे पुराने aspx फ़ाइलें) बनाने की आवश्यकता है। यदि आप ?aspxerrorpath=/er/not/foundउरल्स में रहना पसंद करते हैं तो आपका समाधान ठीक है।
गुटके

7
यह वास्तव में अजीब लग सकता है - लेकिन मेरा जवाब उम्र पहले प्रदान किया गया था और मैं आपके @Gutek से सहमत हूं, मुझे अब किसी त्रुटि पृष्ठ पर रीडायरेक्ट करना पसंद नहीं है । मैं (मेरे उत्तर की ओर देखें: पी)। यदि त्रुटि / कुछ / संसाधन पर आई है .. तो उस संसाधन को 404 या 500 वापस करना चाहिए, आदि मेसिव एसईओ निहितार्थ अन्यथा। आह .. कितनी बार बदलते हैं :)
Pure.Krome

@Gutek क्या आप कस्टम-रीडर्स के बारे में जानते हैं रीडायरेक्ट = "रेस्पॉन्सराइट"? और 404 की वापसी एक सुरक्षा दृष्टिकोण से आदर्श नहीं है
जोवेन

1
@ क्रिस <अपने पसंदीदा देवता को यहाँ डालें> लानत है। मुझे यह भी याद नहीं है कि यह अब क्या था। खैर, बचाव के लिए मेरा मेम संग्रह ... और .. तय।
प्योर.क्रोम

86

मैंने एक एलओटी की जांच की है कि एमवीसी (विशेष रूप से एमवीसी 3 ) में 404 को ठीक से कैसे प्रबंधित किया जाए , और यह, IMHO सबसे अच्छा समाधान है जो मैं लेकर आया हूं:

Global.asax में:

public class MvcApplication : HttpApplication
{
    protected void Application_EndRequest()
    {
        if (Context.Response.StatusCode == 404)
        {
            Response.Clear();

            var rd = new RouteData();
            rd.DataTokens["area"] = "AreaName"; // In case controller is in another area
            rd.Values["controller"] = "Errors";
            rd.Values["action"] = "NotFound";

            IController c = new ErrorsController();
            c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
        }
    }
}

ErrorsController:

public sealed class ErrorsController : Controller
{
    public ActionResult NotFound()
    {
        ActionResult result;

        object model = Request.Url.PathAndQuery;

        if (!Request.IsAjaxRequest())
            result = View(model);
        else
            result = PartialView("_NotFound", model);

        return result;
    }
}

(वैकल्पिक)

स्पष्टीकरण:

AFAIK, 6 अलग-अलग मामले हैं जो ASP.NET MVC3 ऐप 404s उत्पन्न कर सकते हैं।

(ASP.NET फ्रेमवर्क द्वारा स्वचालित रूप से उत्पन्न :)

(1) मार्ग तालिका में एक URL को मैच नहीं मिलता है।

(ASP.NET MVC फ्रेमवर्क द्वारा स्वचालित रूप से उत्पन्न :)

(2) एक URL रूट टेबल में एक मैच पाता है, लेकिन एक गैर-मौजूद नियंत्रक को निर्दिष्ट करता है।

(3) एक URL रूट तालिका में एक मैच पाता है, लेकिन एक गैर-मौजूद कार्रवाई को निर्दिष्ट करता है।

(मैन्युअल रूप से उत्पन्न :)

(4) HttpNotFound () विधि का उपयोग करके एक क्रिया एक HttpNotFoundResult देता है।

(५) एक्शन कोड ४०४ के साथ एक HttpException फेंकता है।

(6) एक क्रिया मैन्युअल रूप से Response.StatusCode प्रॉपर्टी को 404 में संशोधित करती है।

आम तौर पर, आप 3 उद्देश्यों को पूरा करना चाहते हैं:

(1) उपयोगकर्ता को एक कस्टम 404 त्रुटि पृष्ठ दिखाएं।

(2) ग्राहक प्रतिक्रिया (एसईओ के लिए विशेष रूप से महत्वपूर्ण) पर 404 स्थिति कोड बनाए रखें।

(३) ३०२ पुनर्निर्देशन शामिल किए बिना, सीधे प्रतिक्रिया भेजें।

इसे पूरा करने के लिए विभिन्न तरीके हैं:

(1)

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

इस समाधान के साथ समस्याएँ:

  1. मामलों (1), (4), (6) में उद्देश्य (1) का अनुपालन नहीं करता है।
  2. स्वचालित रूप से उद्देश्य (2) का अनुपालन नहीं करता है। इसे मैन्युअल रूप से प्रोग्राम किया जाना चाहिए।
  3. उद्देश्य (3) का अनुपालन नहीं करता है।

(2)

<system.webServer>
    <httpErrors errorMode="Custom">
        <remove statusCode="404"/>
        <error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
    </httpErrors>
</system.webServer>

इस समाधान के साथ समस्याएँ:

  1. केवल IIS 7+ पर काम करता है।
  2. मामलों (2), (3), (5) में उद्देश्य (1) का अनुपालन नहीं करता है।
  3. स्वचालित रूप से उद्देश्य (2) का अनुपालन नहीं करता है। इसे मैन्युअल रूप से प्रोग्राम किया जाना चाहिए।

(3)

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

इस समाधान के साथ समस्याएँ:

  1. केवल IIS 7+ पर काम करता है।
  2. स्वचालित रूप से उद्देश्य (2) का अनुपालन नहीं करता है। इसे मैन्युअल रूप से प्रोग्राम किया जाना चाहिए।
  3. यह एप्लिकेशन स्तर http अपवादों को अस्पष्ट करता है। जैसे customErrors अनुभाग, System.Web.Mvc.HandleErrorAttribute, आदि का उपयोग नहीं कर सकते। यह केवल सामान्य त्रुटि पृष्ठ नहीं दिखा सकता है।

(4)

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

तथा

<system.webServer>
    <httpErrors errorMode="Custom">
        <remove statusCode="404"/>
        <error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
    </httpErrors>
</system.webServer>

इस समाधान के साथ समस्याएँ:

  1. केवल IIS 7+ पर काम करता है।
  2. स्वचालित रूप से उद्देश्य (2) का अनुपालन नहीं करता है। इसे मैन्युअल रूप से प्रोग्राम किया जाना चाहिए।
  3. मामलों (2), (3), (5) में उद्देश्य (3) का अनुपालन नहीं करता है।

जो लोग इससे पहले भी परेशान हो चुके हैं, उन्होंने अपना स्वयं का पुस्तकालय बनाने की कोशिश की (देखें http://aboutcode.net/2011/02/26/handling-not-found-with-asp-net-mvc3.html )। लेकिन पिछले समाधान बाहरी पुस्तकालय का उपयोग करने की जटिलता के बिना सभी मामलों को कवर करने के लिए लगता है।


बहुत बढ़िया जवाब। कई और अपवित्रों के लायक। आपका Global.asax कोड Application_Error में काम क्यों नहीं करता / करती है।
निंजानई

7
धन्यवाद! यह Application_Error के तहत नहीं किया जा सकता है, क्योंकि एक नियंत्रक से फेंके गए स्पष्ट 404 ASP.NET पर त्रुटियों को नहीं माना जाता है। यदि आप नियंत्रक से HttpNotFound () लौटाते हैं, तो Application_Error ईवेंट कभी ट्रिगर नहीं होगा।
मार्को Mar

1
मुझे लगता है कि आप public ActionResult NotFound() {}अपने ErrorsController में भूल गए । इसके अलावा, क्या आप बता सकते हैं कि _NotFoundAJAX के अनुरोधों के लिए आपका आंशिक कैसा दिखेगा?
d4n3

2
MVC 4 के साथ मैं हमेशा MissingMethodException: Cannot create an abstract classलाइन पर मिलता हूं c.Execute(new RequestContext(new HttpContextWrapper(Context), rd)); कोई विचार?
µBio

1
यदि "नहीं मिला" URL में पथ में एक डॉट शामिल है (जैसे example.com/hi.bob ) तो Application_EndRequest में बिल्कुल भी आग नहीं लगती है, और मुझे IE का जेनेरिक 404 पेज मिलता है।
Bob.at.Indigo.Health 14-14 '

13

मुझे वास्तव में कॉटसैक्स का समाधान पसंद है और लगता है कि इसकी बहुत स्पष्ट रूप से व्याख्या की गई है। मेरा एकमात्र अतिरिक्त चरण 2 में परिवर्तन करना था

public abstract class MyController : Controller
{

    #region Http404 handling

    protected override void HandleUnknownAction(string actionName)
    {
        //if controller is ErrorController dont 'nest' exceptions
        if(this.GetType() != typeof(ErrorController))
        this.InvokeHttp404(HttpContext);
    }

    public ActionResult InvokeHttp404(HttpContextBase httpContext)
    {
        IController errorController = ObjectFactory.GetInstance<ErrorController>();
        var errorRoute = new RouteData();
        errorRoute.Values.Add("controller", "Error");
        errorRoute.Values.Add("action", "Http404");
        errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
        errorController.Execute(new RequestContext(
             httpContext, errorRoute));

        return new EmptyResult();
    }

    #endregion
}

मूल रूप से यह दो बार अपवाद दिनचर्या को ट्रिगर करने से अमान्य कार्यों और नियंत्रकों वाले यूआरएल को रोकता है। उदाहरण के लिए जैसे कि asdfsdf / dfgdfgd


4
यह उत्कृष्ट है। वे "दो बार" मामले मुझे परेशान करने लगे थे। मेरे उत्तर को अपडेट किया
मैट कोकाज

यदि उपयोगकर्ता गलत नियंत्रक और कार्रवाई नाम दर्ज करता है तो उपरोक्त समाधान बिल्कुल काम नहीं करता है?
मोनोजित सरकार

6

अवैध नियंत्रकों के लिए काम करने के लिए मुझे @ cottsak की विधि प्राप्त हो सकती है एकमात्र तरीका, CustomControllerFactory में मौजूदा मार्ग अनुरोध को संशोधित करना था, जैसे:

public class CustomControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        try
        {
            if (controllerType == null)
                return base.GetControllerInstance(requestContext, controllerType); 
            else
                return ObjectFactory.GetInstance(controllerType) as Controller;
        }
        catch (HttpException ex)
        {
            if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound)
            {
                requestContext.RouteData.Values["controller"] = "Error";
                requestContext.RouteData.Values["action"] = "Http404";
                requestContext.RouteData.Values.Add("url", requestContext.HttpContext.Request.Url.OriginalString);

                return ObjectFactory.GetInstance<ErrorController>();
            }
            else
                throw ex;
        }
    }
}

मुझे उल्लेख करना चाहिए कि मैं एमवीसी 2.0 का उपयोग कर रहा हूं।


तुम जानते हो क्यों? (MVC2 विशिष्ट?)
मैट कोकाज

मुझे लगता है कि कुंजी एक नया बनाने के बजाय मौजूदा अनुरोध को संशोधित करना था, लेकिन मैंने यह थोड़ी देर पहले किया था इसलिए मुझे यकीन नहीं है कि यह था। "InvokeHttp404" नियंत्रक कारखाने से काम नहीं किया।
डेव के

मैंने आज कुछ MVC2 बारीकियों के साथ अपना जवाब अपडेट किया है। क्या आप मुझे बता सकते हैं कि क्या ऊपर दिए गए उपाय के रूप में मेरा समाधान अभी भी आपके लिए कारगर नहीं है?
मैट कोकाज

4

यहां एमवीसी टूल का उपयोग करने का एक और तरीका है जिसे आप खराब नियंत्रक नाम, खराब मार्ग के नाम और किसी भी अन्य मानदंड के अनुरोधों को संभाल सकते हैं जो आप किसी एक्शन विधि के अंदर फिट देखते हैं। व्यक्तिगत रूप से, मैं संभव के रूप में कई web.config सेटिंग्स से बचना पसंद करता हूं, क्योंकि वे 302/200 रीडायरेक्ट करते हैं और Server.Transferरेज़र व्यू का उपयोग करके ResponseRewrite ( ) का समर्थन नहीं करते हैं। मैं एसईओ कारणों के लिए एक कस्टम त्रुटि पृष्ठ के साथ 404 वापस करना चाहता हूं।

इसमें से कुछ ऊपर cottsak की तकनीक पर नया है।

यह समाधान MVC 3 त्रुटि फ़िल्टर के पक्ष में न्यूनतम web.config सेटिंग्स का भी उपयोग करता है।

प्रयोग

बस एक कार्रवाई या कस्टम ActionFilterAttribute से एक HttpException फेंक दें।

Throw New HttpException(HttpStatusCode.NotFound, "[Custom Exception Message Here]")

चरण 1

निम्नलिखित सेटिंग को अपने web.config में जोड़ें। इसके लिए MVC के हैण्डलेयरअट्रैक्टर का उपयोग करना आवश्यक है।

<customErrors mode="On" redirectMode="ResponseRedirect" />

चरण 2

MVC फ्रेमवर्क के हैंडल के समान एक कस्टम HandleHttpErrorAttribute जोड़ें, HTTP त्रुटियों को छोड़कर:

<AttributeUsage(AttributeTargets.All, AllowMultiple:=True)>
Public Class HandleHttpErrorAttribute
    Inherits FilterAttribute
    Implements IExceptionFilter

    Private Const m_DefaultViewFormat As String = "ErrorHttp{0}"

    Private m_HttpCode As HttpStatusCode
    Private m_Master As String
    Private m_View As String

    Public Property HttpCode As HttpStatusCode
        Get
            If m_HttpCode = 0 Then
                Return HttpStatusCode.NotFound
            End If
            Return m_HttpCode
        End Get
        Set(value As HttpStatusCode)
            m_HttpCode = value
        End Set
    End Property

    Public Property Master As String
        Get
            Return If(m_Master, String.Empty)
        End Get
        Set(value As String)
            m_Master = value
        End Set
    End Property

    Public Property View As String
        Get
            If String.IsNullOrEmpty(m_View) Then
                Return String.Format(m_DefaultViewFormat, Me.HttpCode)
            End If
            Return m_View
        End Get
        Set(value As String)
            m_View = value
        End Set
    End Property

    Public Sub OnException(filterContext As System.Web.Mvc.ExceptionContext) Implements System.Web.Mvc.IExceptionFilter.OnException
        If filterContext Is Nothing Then Throw New ArgumentException("filterContext")

        If filterContext.IsChildAction Then
            Return
        End If

        If filterContext.ExceptionHandled OrElse Not filterContext.HttpContext.IsCustomErrorEnabled Then
            Return
        End If

        Dim ex As HttpException = TryCast(filterContext.Exception, HttpException)
        If ex Is Nothing OrElse ex.GetHttpCode = HttpStatusCode.InternalServerError Then
            Return
        End If

        If ex.GetHttpCode <> Me.HttpCode Then
            Return
        End If

        Dim controllerName As String = filterContext.RouteData.Values("controller")
        Dim actionName As String = filterContext.RouteData.Values("action")
        Dim model As New HandleErrorInfo(filterContext.Exception, controllerName, actionName)

        filterContext.Result = New ViewResult With {
            .ViewName = Me.View,
            .MasterName = Me.Master,
            .ViewData = New ViewDataDictionary(Of HandleErrorInfo)(model),
            .TempData = filterContext.Controller.TempData
        }
        filterContext.ExceptionHandled = True
        filterContext.HttpContext.Response.Clear()
        filterContext.HttpContext.Response.StatusCode = Me.HttpCode
        filterContext.HttpContext.Response.TrySkipIisCustomErrors = True
    End Sub
End Class

चरण 3

GlobalFilterCollection ( GlobalFilters.Filters) में फ़िल्टर जोड़ें Global.asax। यह उदाहरण सभी InternalServerError (500) त्रुटियों को त्रुटि साझा दृश्य ( Views/Shared/Error.vbhtml) में बदल देगा। NotFound (404) त्रुटियों को साझा किए गए विचारों में भी ErrorHttp404.vbhtml को भेजा जाएगा। मैंने आपको यह दिखाने के लिए 401 त्रुटि जोड़ी है कि यह अतिरिक्त HTTP त्रुटि कोड के लिए कैसे बढ़ाया जा सकता है। ध्यान दें कि ये साझा विचार होने चाहिए, और वे सभी System.Web.Mvc.HandleErrorInfoमॉडल के रूप में ऑब्जेक्ट का उपयोग करते हैं ।

filters.Add(New HandleHttpErrorAttribute With {.View = "ErrorHttp401", .HttpCode = HttpStatusCode.Unauthorized})
filters.Add(New HandleHttpErrorAttribute With {.View = "ErrorHttp404", .HttpCode = HttpStatusCode.NotFound})
filters.Add(New HandleErrorAttribute With {.View = "Error"})

चरण 4

एक बेस कंट्रोलर क्लास बनाएं और इसे अपने कंट्रोलर्स से इनहेरिट करें। यह चरण हमें अज्ञात एक्शन नामों को संभालने और HTTP 404 त्रुटि को हमारे HandleHttpErrorAttribute को उठाने की अनुमति देता है।

Public Class BaseController
    Inherits System.Web.Mvc.Controller

    Protected Overrides Sub HandleUnknownAction(actionName As String)
        Me.ActionInvoker.InvokeAction(Me.ControllerContext, "Unknown")
    End Sub

    Public Function Unknown() As ActionResult
        Throw New HttpException(HttpStatusCode.NotFound, "The specified controller or action does not exist.")
        Return New EmptyResult
    End Function
End Class

चरण 5

एक नियंत्रक फ़ॉरेस्ट ओवरराइड बनाएँ, और Application_Start में अपनी Global.asax फ़ाइल में इसे ओवरराइड करें। यह चरण हमें HTTP 404 अपवाद को बढ़ाने की अनुमति देता है जब एक अवैध नियंत्रक नाम निर्दिष्ट किया गया है।

Public Class MyControllerFactory
    Inherits DefaultControllerFactory

    Protected Overrides Function GetControllerInstance(requestContext As System.Web.Routing.RequestContext, controllerType As System.Type) As System.Web.Mvc.IController
        Try
            Return MyBase.GetControllerInstance(requestContext, controllerType)
        Catch ex As HttpException
            Return DependencyResolver.Current.GetService(Of BaseController)()
        End Try
    End Function
End Class

'In Global.asax.vb Application_Start:

controllerBuilder.Current.SetControllerFactory(New MyControllerFactory)

चरण 6

BaseController अज्ञात कार्रवाई के लिए अपने RoutTable.Routes में एक विशेष मार्ग शामिल करें। यह हमें उस मामले में 404 जुटाने में मदद करेगा जहां एक उपयोगकर्ता किसी अज्ञात नियंत्रक, या अज्ञात कार्रवाई तक पहुंचता है।

'BaseController
routes.MapRoute( _
    "Unknown", "BaseController/{action}/{id}", _
    New With {.controller = "BaseController", .action = "Unknown", .id = UrlParameter.Optional} _
)

सारांश

इस उदाहरण ने प्रदर्शित किया कि फ़िल्टर विशेषताओं और साझा त्रुटि विचारों का उपयोग करके पुनर्निर्देशित के बिना ब्राउज़र में 404 Http त्रुटि कोड वापस करने के लिए MVC फ्रेमवर्क का उपयोग कैसे किया जा सकता है। यह उसी कस्टम त्रुटि पृष्ठ को प्रदर्शित करता है जब अमान्य नियंत्रक नाम और कार्रवाई नाम निर्दिष्ट किए जाते हैं।

यदि मुझे एक = एक पोस्ट करने के लिए पर्याप्त वोट मिलते हैं, तो मैं एक अवैध नियंत्रक नाम, एक्शन नाम, और होम / ट्राइगरनॉटफाउंड एक्शन से उठाए गए एक कस्टम 404 का स्क्रीनशॉट जोड़ूंगा। जब मैं इस समाधान का उपयोग करते हुए निम्नलिखित URL तक पहुँचता हूँ तो फ़िडलर 404 संदेश देता है:

/InvalidController
/Home/InvalidRoute
/InvalidController/InvalidRoute
/Home/TriggerNotFound

ऊपर कोट्सक की पोस्ट और ये लेख अच्छे संदर्भ थे।


हम्म, मैं यह काम करने के लिए नहीं मिल सकता है: The IControllerFactory 'aaa.bbb.CustomControllerFactory' did not return a controller for the name '123'.- कोई भी विचार क्यों मुझे मिलेगा?
enashnash

redirectMode = "ResponseRedirect"। यह एक 302 पाया + 200 ठीक लौटेगा जो एसईओ के लिए अच्छा नहीं है!
पूसइन्बूट्स

4

मेरा छोटा समाधान जो अखंडित क्षेत्रों, नियंत्रकों और क्रियाओं के साथ काम करता है:

  1. एक दृश्य 404.cshtml बनाएँ।

  2. अपने नियंत्रकों के लिए एक आधार वर्ग बनाएँ:

    public class Controller : System.Web.Mvc.Controller
    {
        protected override void HandleUnknownAction(string actionName)
        {
            Http404().ExecuteResult(ControllerContext);
        }
    
        protected virtual ViewResult Http404()
        {
            Response.StatusCode = (int)HttpStatusCode.NotFound;
            return View("404");
        }
    }
  3. एक कस्टम कंट्रोलर फ़ैक्टरी बनाएं जो आपके आधार नियंत्रक को कमबैक के रूप में लौटाए:

    public class ControllerFactory : DefaultControllerFactory
    {
        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            if (controllerType != null)
                return base.GetControllerInstance(requestContext, controllerType);
    
            return new Controller();
        }
    }
  4. Application_Start()निम्नलिखित पंक्ति में जोड़ें :

    ControllerBuilder.Current.SetControllerFactory(typeof(ControllerFactory));

3

MVC4 WebAPI 404 में निम्नलिखित तरीके से हैंडल किया जा सकता है,

पाठ्यक्रम APICONTROLLER

    // GET /api/courses/5
    public HttpResponseMessage<Courses> Get(int id)
    {
        HttpResponseMessage<Courses> resp = null;

        var aCourse = _courses.Where(c => c.Id == id).FirstOrDefault();

        resp = aCourse == null ? new HttpResponseMessage<Courses>(System.Net.HttpStatusCode.NotFound) : new HttpResponseMessage<Courses>(aCourse);

        return resp;
    }

गृह नियंत्रण

public ActionResult Course(int id)
{
    return View(id);
}

राय

<div id="course"></div>
<script type="text/javascript">
    var id = @Model;
    var course = $('#course');
    $.ajax({    
        url: '/api/courses/' + id,
        success: function (data) {
            course.text(data.Name);
        },
        statusCode: {
            404: function() 
            {
                course.text('Course not available!');    
            }
        }
    });
</script>

ग्लोबल

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

परिणाम

यहां छवि विवरण दर्ज करें


2

नगेट पर NotFoundMVC का प्रयास करें। यह काम करता है, कोई सेटअप नहीं।


http://localhost/Views/Shared/NotFound.cshtmlकस्टम 404 पृष्ठ में परिणाम नहीं होता है।
डेन फ्राइडमैन

इसे कस्टमाइज़ करना बहुत आसान है। आपके पास अनुरोधित url और रेफ़रर तक पहुंच है, इसलिए आप वह कर सकते हैं जो आपको पसंद है। मैं इस पैकेज का उपयोग करता हूं, और यह वास्तव में अच्छी तरह से काम करता है।
एवरोहोम यिसरेल

यह एक शानदार पैकेज है, बशर्ते आप async टास्क <ActionResult> क्रियाएँ (या अन्य समान async) क्रियाओं का उपयोग नहीं करेंगे। MVC 5 पर यह एक टूटा हुआ परिदृश्य है। GitHub पर एक कांटा है जो इसे दरकिनार करता है, लेकिन मेरे लिए यह एक नहीं, नहीं है।
स्टारगज़र

2

मेरा समाधान, यदि कोई इसे उपयोगी पाता है।

Web.config में:

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

इन Controllers/ErrorController.cs:

public class ErrorController : Controller
{
    public ActionResult PageNotFound()
    {
        if(Request.IsAjaxRequest()) {
            Response.StatusCode = (int)HttpStatusCode.NotFound;
            return Content("Not Found", "text/plain");
        }

        return View();
    }
}

फ़ोल्डर PageNotFound.cshtmlमें एक जोड़ें Shared, और यह बात है।


2
क्या यह 302 पुनर्निर्देशित नहीं करता है फिर ग्राहक को 200 (ओके) का दर्जा? क्या उन्हें अभी भी 404 का दर्जा नहीं मिल रहा है?
सैम

@Konamiman क्या आपको यकीन है कि आपके कोड की लाइन को पढ़ना चाहिए model.RequestedUrl = Request.Url.OriginalString.Contains(url) & Request.Url.OriginalString != url ? Request.Url.OriginalString : url;और नहीं model.RequestedUrl = Request.Url.OriginalString.Contains(url) && Request.Url.OriginalString != url ? Request.Url.OriginalString : url;(& के बजाय &&)?
जीन-फ्रांस्वा ब्यूचैम्प

2

यह मुझे लगता है कि मानक CustomErrorsविन्यास को बस काम करना चाहिए , क्योंकि इस पर निर्भरता के कारण Server.Transferऐसा लगता है कि आंतरिक कार्यान्वयन ResponseRewriteMVC के साथ संगत नहीं है।

यह मेरे लिए एक चमकदार कार्यक्षमता छेद जैसा लगता है, इसलिए मैंने HTTP मॉड्यूल का उपयोग करके इस सुविधा को फिर से लागू करने का निर्णय लिया। नीचे दिए गए समाधान से आप किसी भी MVC मार्ग को पुनर्निर्देशित करके किसी भी HTTP स्थिति कोड (404 सहित) को संभाल सकते हैं, जैसा कि आप सामान्य रूप से करते हैं।

<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite">
    <error statusCode="404" redirect="404.aspx" />
    <error statusCode="500" redirect="~/MVCErrorPage" />
</customErrors>

यह निम्नलिखित प्लेटफार्मों पर परीक्षण किया गया है;

  • एकीकृत पाइपलाइन मोड में MVC4 (IIS एक्सप्रेस 8)
  • क्लासिक मोड में MVC4 (VS विकास सर्वर, कैसिनी)
  • MVC4 क्लासिक मोड में (IIS6)

लाभ

  • जेनेरिक समाधान जो किसी भी एमवीसी परियोजना में गिराया जा सकता है
  • पारंपरिक कस्टम त्रुटियों कॉन्फ़िगरेशन के लिए समर्थन सक्षम करता है
  • एकीकृत पाइपलाइन और क्लासिक मोड दोनों में काम करता है

समाधान

namespace Foo.Bar.Modules {

    /// <summary>
    /// Enables support for CustomErrors ResponseRewrite mode in MVC.
    /// </summary>
    public class ErrorHandler : IHttpModule {

        private HttpContext HttpContext { get { return HttpContext.Current; } }
        private CustomErrorsSection CustomErrors { get; set; }

        public void Init(HttpApplication application) {
            System.Configuration.Configuration configuration = WebConfigurationManager.OpenWebConfiguration("~");
            CustomErrors = (CustomErrorsSection)configuration.GetSection("system.web/customErrors");

            application.EndRequest += Application_EndRequest;
        }

        protected void Application_EndRequest(object sender, EventArgs e) {

            // only handle rewrite mode, ignore redirect configuration (if it ain't broke don't re-implement it)
            if (CustomErrors.RedirectMode == CustomErrorsRedirectMode.ResponseRewrite && HttpContext.IsCustomErrorEnabled) {

                int statusCode = HttpContext.Response.StatusCode;

                // if this request has thrown an exception then find the real status code
                Exception exception = HttpContext.Error;
                if (exception != null) {
                    // set default error status code for application exceptions
                    statusCode = (int)HttpStatusCode.InternalServerError;
                }

                HttpException httpException = exception as HttpException;
                if (httpException != null) {
                    statusCode = httpException.GetHttpCode();
                }

                if ((HttpStatusCode)statusCode != HttpStatusCode.OK) {

                    Dictionary<int, string> errorPaths = new Dictionary<int, string>();

                    foreach (CustomError error in CustomErrors.Errors) {
                        errorPaths.Add(error.StatusCode, error.Redirect);
                    }

                    // find a custom error path for this status code
                    if (errorPaths.Keys.Contains(statusCode)) {
                        string url = errorPaths[statusCode];

                        // avoid circular redirects
                        if (!HttpContext.Request.Url.AbsolutePath.Equals(VirtualPathUtility.ToAbsolute(url))) {

                            HttpContext.Response.Clear();
                            HttpContext.Response.TrySkipIisCustomErrors = true;

                            HttpContext.Server.ClearError();

                            // do the redirect here
                            if (HttpRuntime.UsingIntegratedPipeline) {
                                HttpContext.Server.TransferRequest(url, true);
                            }
                            else {
                                HttpContext.RewritePath(url, false);

                                IHttpHandler httpHandler = new MvcHttpHandler();
                                httpHandler.ProcessRequest(HttpContext);
                            }

                            // return the original status code to the client
                            // (this won't work in integrated pipleline mode)
                            HttpContext.Response.StatusCode = statusCode;

                        }
                    }

                }

            }

        }

        public void Dispose() {

        }


    }

}

प्रयोग

इसे अपने web.config में अंतिम HTTP मॉड्यूल के रूप में शामिल करें

  <system.web>
    <httpModules>
      <add name="ErrorHandler" type="Foo.Bar.Modules.ErrorHandler" />
    </httpModules>
  </system.web>

  <!-- IIS7+ -->
  <system.webServer>
    <modules>
      <add name="ErrorHandler" type="Foo.Bar.Modules.ErrorHandler" />
    </modules>
  </system.webServer>

आप जिन पर ध्यान दे रहे हैं उनके लिए आप देखेंगे कि एकीकृत पाइपलाइन मोड में यह हमेशा HTTP 200 के साथ Server.TransferRequestकाम करने के तरीके के कारण प्रतिक्रिया देगा । उचित त्रुटि कोड को वापस करने के लिए मैं निम्नलिखित त्रुटि नियंत्रक का उपयोग करता हूं।

public class ErrorController : Controller {

    public ErrorController() { }

    public ActionResult Index(int id) {
        // pass real error code to client
        HttpContext.Response.StatusCode = id;
        HttpContext.Response.TrySkipIisCustomErrors = true;

        return View("Errors/" + id.ToString());
    }

}

2

ASP.NET MVC में त्रुटियों से निपटना बट में दर्द है। मैंने इस पृष्ठ पर और अन्य प्रश्नों और साइटों पर बहुत सारे सुझावों की कोशिश की और कुछ भी अच्छा नहीं हुआ। एक सुझाव यह था कि web.config के अंदर त्रुटियों को संभालना system.webserver लेकिन सिर्फ खाली पन्नों को लौटाता है

इस समाधान के साथ आने पर मेरा लक्ष्य था;

  • कमी नहीं है
  • डिफ़ॉल्ट त्रुटि हैंडलिंग की तरह 200 / ओके नहीं प्रॉपर स्टेटस कॉडेस लौटाएँ

यहाँ मेरा समाधान है।

1। निम्न को system.web अनुभाग में जोड़ें

   <system.web>
     <customErrors mode="On" redirectMode="ResponseRewrite">
      <error statusCode="404"  redirect="~/Error/404.aspx" />
      <error statusCode="500" redirect="~/Error/500.aspx" />
     </customErrors>
    <system.web>

उपरोक्त मार्गों को किसी भी url द्वारा हैंडल नहीं किया गया है जो कि मार्गों द्वारा नियंत्रित नहीं हैं। सूचना मैं aspx नहीं html का इस्तेमाल किया । ऐसा इसलिए है कि मैं पीछे कोड पर एक प्रतिक्रिया कोड जोड़ सकता हूं ।

। अपने प्रोजेक्ट के मूल में त्रुटि (या जो भी आप चाहें) नामक एक फ़ोल्डर बनाएँ और दो वेबफ़ॉर्म जोड़ें। नीचे मेरा 404 पेज है;

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="404.aspx.cs" Inherits="Myapp.Error._404" %>

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title >Page Not found</title>
    <link href="<%=ResolveUrl("~/Content/myapp.css")%>" rel="stylesheet" />
</head>
<body>
    <div class="top-nav">
      <a runat="server" class="company-logo" href="~/"></a>
    </div>
    <div>
        <h1>404 - Page Not found</h1>
        <p>The page you are looking for cannot be found.</p>
        <hr />
        <footer></footer>
    </div>
</body>
</html>

और पीछे के कोड पर मैंने प्रतिक्रिया कोड निर्धारित किया है

protected void Page_Load(object sender, EventArgs e)
{
    Response.StatusCode = 404;
}

500 पेज के लिए भी ऐसा ही करें

3। नियंत्रक के भीतर त्रुटियों को संभालने के लिए। इसे करने के कई तरीके हैं। इसी से मेरा काम बना है। मेरे सभी नियंत्रक एक बेस कंट्रोलर से विरासत में मिले हैं। आधार नियंत्रक में, मेरे पास निम्नलिखित विधियाँ हैं

protected ActionResult ShowNotFound()
{
    return ShowNotFound("Page not found....");
}

protected ActionResult ShowNotFound(string message)
{
    return ShowCustomError(HttpStatusCode.NotFound, message);
}

protected ActionResult ShowServerError()
{
    return ShowServerError("Application error....");
}

protected ActionResult ShowServerError(string message)
{
    return ShowCustomError(HttpStatusCode.InternalServerError, message);
}

protected ActionResult ShowNotAuthorized()
{
    return ShowNotAuthorized("You are not allowed ....");

}

protected ActionResult ShowNotAuthorized(string message)
{
    return ShowCustomError(HttpStatusCode.Forbidden, message);
}

protected ActionResult ShowCustomError(HttpStatusCode statusCode, string message)
{
    Response.StatusCode = (int)statusCode;
    string title = "";
    switch (statusCode)
    {
        case HttpStatusCode.NotFound:
            title = "404 - Not found";
            break;
        case HttpStatusCode.Forbidden:
            title = "403 - Access Denied";
            break;
        default:
            title = "500 - Application Error";
            break;
    }
    ViewBag.Title = title;
    ViewBag.Message = message;
    return View("CustomError");
}

4। अपने साझा विचार फ़ोल्डर में CustomError.cshtml जोड़ें । नीचे मेरा है;

<h1>@ViewBag.Title</h1>
<br />
<p>@ViewBag.Message</p>

अब आपके एप्लिकेशन कंट्रोलर में आप कुछ इस तरह से कर सकते हैं;

public class WidgetsController : ControllerBase
{
  [HttpGet]
  public ActionResult Edit(int id)
  {
    Try
    {
       var widget = db.getWidgetById(id);
       if(widget == null)
          return ShowNotFound();
          //or return ShowNotFound("Invalid widget!");
       return View(widget);
    }
    catch(Exception ex)
    {
       //log error
       logger.Error(ex)
       return ShowServerError();
    }
  }
}

अब कैवियट के लिए । यह स्थिर फ़ाइल त्रुटियों को हैंडल नहीं करेगा। इसलिए यदि आपके पास एक मार्ग है जैसे example.com/widgets और उपयोगकर्ता इसे example.com/widgets.html में बदल देते हैं , तो उन्हें IIS डिफ़ॉल्ट त्रुटि पृष्ठ मिल जाएगा, इसलिए आपको IIS स्तर की त्रुटियों को किसी अन्य तरीके से संभालना होगा।


1

जवाब पोस्ट करने के बाद से मेरी टिप्पणी बहुत लंबी थी ...

यह गेंडा पोस्ट / उत्तर के लिए एक टिप्पणी और प्रश्न दोनों है:

https://stackoverflow.com/a/7499406/687549

मैं इस जवाब को दूसरों के लिए पसंद करता हूँ क्योंकि यह सरलता है और तथ्य यह है कि स्पष्ट रूप से Microsoft के कुछ लोगों से सलाह ली गई थी। मुझे हालांकि तीन सवाल मिले और अगर उनका जवाब दिया जा सकता है तो मैं इस जवाब को ASP.NET MVC (x) ऐप के लिए इंटरव्यू पर सभी 404/500 त्रुटि उत्तरों की पवित्र कब्र कहूंगा।

@ Pure.Krome

  1. क्या आप GWB द्वारा बताई गई टिप्पणियों से एसईओ सामग्री के साथ अपना उत्तर अपडेट कर सकते हैं (आपके उत्तर में इसका कोई उल्लेख नहीं था - <customErrors mode="On" redirectMode="ResponseRewrite">और <httpErrors errorMode="Custom" existingResponse="Replace">?

  2. क्या आप अपने ASP.NET टीम के दोस्तों से पूछ सकते हैं कि क्या ऐसा करना ठीक है - कुछ पुष्टि करना अच्छा होगा - शायद यह बदलने के लिए एक बड़ा नहीं-नहीं है redirectModeऔर existingResponseइस तरह से एसईओ के साथ अच्छी तरह से खेलने में सक्षम हो सकता है ?!

  3. आप कुछ और सामान आसपास के स्पष्टीकरण को जोड़ सकते हैं ( customErrors redirectMode="ResponseRewrite", customErrors redirectMode="ResponseRedirect", httpErrors errorMode="Custom" existingResponse="Replace", हटाने customErrorsपूरी तरह कोई सुझाव) माइक्रोसॉफ्ट पर अपने मित्रों से बात कर के बाद?

जैसा कि मैं कह रहा था; यदि हम आपके उत्तर को और अधिक पूर्ण बना सकते हैं तो यह 54 000+ दृश्यों के साथ एक काफी लोकप्रिय प्रश्न प्रतीत होता है।

अद्यतन : यूनिकॉर्न का उत्तर 302 मिला और 200 ठीक है और केवल एक मार्ग का उपयोग करके वापस 404 में नहीं बदला जा सकता है। यह एक भौतिक फ़ाइल होना चाहिए जो बहुत MVC नहीं है: ish। इसलिए दूसरे समाधान पर आगे बढ़ रहे हैं। बहुत बुरा है क्योंकि यह परम MVC लग रहा था: ish जवाब इस तक।


1

मेरे समाधान को जोड़ना, जो हर्मन कान के लगभग समान है, एक छोटी सी शिकन के साथ इसे मेरी परियोजना के लिए काम करने की अनुमति देता है।

एक कस्टम त्रुटि नियंत्रक बनाएँ:

public class Error404Controller : BaseController
{
    [HttpGet]
    public ActionResult PageNotFound()
    {
        Response.StatusCode = 404;
        return View("404");
    }
}

फिर एक कस्टम नियंत्रक कारखाना बनाएँ:

public class CustomControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        return controllerType == null ? new Error404Controller() : base.GetControllerInstance(requestContext, controllerType);
    }
}

अंत में, कस्टम त्रुटि नियंत्रक में एक ओवरराइड जोड़ें:

protected override void HandleUnknownAction(string actionName)
{
    var errorRoute = new RouteData();
    errorRoute.Values.Add("controller", "Error404");
    errorRoute.Values.Add("action", "PageNotFound");
    new Error404Controller().Execute(new RequestContext(HttpContext, errorRoute));
}

और बस। Web.config परिवर्तनों की कोई आवश्यकता नहीं है।


1

1) अमूर्त नियंत्रक वर्ग बनाएं।

public abstract class MyController:Controller
{
    public ActionResult NotFound()
    {
        Response.StatusCode = 404;
        return View("NotFound");
    }

    protected override void HandleUnknownAction(string actionName)
    {
        this.ActionInvoker.InvokeAction(this.ControllerContext, "NotFound");
    }
    protected override void OnAuthorization(AuthorizationContext filterContext) { }
}  

2) अपने सभी नियंत्रकों में इस सार वर्ग से विरासत बनाएं

public class HomeController : MyController
{}  

3) और आपको View-Shared फ़ोल्डर में "NotFound" नाम का एक दृश्य जोड़ें।


0

मैं इस धागे पर पोस्ट किए गए अधिकांश समाधानों से गुज़रा। हालांकि यह प्रश्न पुराना हो सकता है, यह अभी भी नई परियोजनाओं के लिए अभी भी लागू है, इसलिए मैंने यहां प्रस्तुत किए गए उत्तरों के साथ-साथ जहां और जहां भी पढ़ा है, पर बहुत समय बिताया है।

जैसा कि @ मर्को ने अलग-अलग मामलों को बताया, जिसके तहत 404 हो सकते हैं, मैंने उस सूची के खिलाफ एक साथ हल किए गए समाधान की जांच की। उनकी आवश्यकताओं की सूची के अलावा, मैंने एक और भी जोड़ा।

  • समाधान सबसे उपयुक्त तरीके से MVC और साथ ही AJAX / WebAPI कॉल को संभालने में सक्षम होना चाहिए। (यानी अगर 404 एमवीसी में होता है, तो उसे नॉट फाउंड पेज दिखाना चाहिए और अगर 404 वेबएपीआई में होता है, तो उसे एक्सएमएल / जेएसएन प्रतिक्रिया को हाईजैक नहीं करना चाहिए ताकि उपभोग जावास्क्रिप्ट आसानी से पार्स कर सके)।

यह समाधान 2 गुना है:

इसका पहला भाग @Guillaume से https://stackoverflow.com/a/27354140/2310818 पर आता है । उनका समाधान किसी भी 404 का ध्यान रखता है जो अमान्य मार्ग, अमान्य नियंत्रक और अमान्य कार्रवाई के कारण हुए थे।

वेबफार्म बनाने का विचार है और फिर इसे अपने एमवीसी एरर्स कंट्रोलर के नोटफाउंड एक्शन को कॉल करें। यह बिना किसी पुनर्निर्देशन के यह सब करता है इसलिए आपको फ़िडलर में एक भी 302 नहीं दिखाई देगा। मूल URL भी संरक्षित है, जो इस समाधान को शानदार बनाता है!


इसका दूसरा भाग @ जर्मेन से https://stackoverflow.com/a/5536676/2310818 पर आता है । उनका समाधान HttpNotFoundResult () के रूप में आपके कार्यों द्वारा लौटाए गए किसी भी 404 का ख्याल रखता है या नए HttpException () को फेंक देता है!

इस विचार की प्रतिक्रिया पर एक फिल्टर देखने के साथ-साथ आपके एमवीसी नियंत्रकों द्वारा फेंके गए अपवाद और आपके त्रुटियाँ नियंत्रक में उचित कार्रवाई को कॉल करना है। फिर से यह समाधान बिना किसी पुनर्निर्देशन के काम करता है और मूल यूआरएल संरक्षित है!


जैसा कि आप देख सकते हैं, ये दोनों समाधान एक साथ एक बहुत ही मजबूत त्रुटि हैंडलिंग तंत्र की पेशकश करते हैं और वे @Marco द्वारा सूचीबद्ध सभी आवश्यकताओं के साथ-साथ मेरी आवश्यकताओं को भी प्राप्त करते हैं। यदि आप एक कार्य नमूना या इस समाधान का एक डेमो देखना चाहते हैं, तो कृपया टिप्पणियों में छोड़ दें और मुझे इसे एक साथ रखने में खुशी होगी।


0

मैं सभी लेखों के माध्यम से चला गया, लेकिन मेरे लिए कुछ भी काम नहीं करता है: मेरी आवश्यकता उपयोगकर्ता को आपके url कस्टम 404 पृष्ठ में कुछ भी दिखाना चाहिए। मुझे लगा कि यह बहुत सीधा है। लेकिन आपको 404 को ठीक से संभालने के बारे में समझना चाहिए:

 <system.web>
    <customErrors mode="On" redirectMode="ResponseRewrite">
      <error statusCode="404" redirect="~/PageNotFound.aspx"/>
    </customErrors>
  </system.web>
<system.webServer>
    <httpErrors errorMode="Custom">
      <remove statusCode="404"/>
      <error statusCode="404" path="/PageNotFound.html" responseMode="ExecuteURL"/>
    </httpErrors>
</system.webServer>

मुझे यह लेख बहुत मददगार लगा। इसे एक बार में पढ़ा जा सकता है। कस्टोम एरर पेज-बेन फोस्टर

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.