asp.net mvc एएसपी.नेट एमवीसी में मैं 404 को कैसे ठीक से संभाल सकता हूं?




asp.net-mvc http-status-code-404 (16)

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

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 का उपयोग कर रहा हूं।

मैं बस एएसपी.नेट एमवीसी पर शुरू कर रहा हूं इसलिए मेरे साथ भालू। मैंने इस साइट और कई अन्य लोगों के आसपास खोज की है और इसके कुछ कार्यान्वयन देखा है।

संपादित करें: मैं उल्लेख करना भूल गया कि मैं आरसी 2 का उपयोग कर रहा हूं

यूआरएल रूटिंग का उपयोग करना:

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

उपर्युक्त इस तरह के अनुरोधों का ख्याल रखना प्रतीत होता है (आरंभिक एमवीसी प्रोजेक्ट द्वारा डिफ़ॉल्ट रूट टेबल सेटअप को मानते हुए): "/ 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 का उपयोग करने के लिए बस डिफ़ॉल्ट करना चाहिए और यह सब भूल जाओ? मुझे लगता है कि अगर मैं कस्टमर के साथ जाता हूं तो मुझे वेब के कारण जेनेरिक 404 पेज / व्यू के बाहर / दृश्यों को स्टोर करना होगा। सीधे पहुंच पर कॉन्फिग प्रतिबंध। वैसे भी किसी भी सर्वोत्तम प्रथाओं या मार्गदर्शन की सराहना की जाती है।


Adding my solution, which is almost identical to Herman Kan's, with a small wrinkle to allow it to work for my project.

Create a custom error controller:

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

Then create a custom controller factory:

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

Finally, add an override to the custom error controller:

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));
}

और बस। No need for Web.config changes.


Posting an answer since my comment was too long...

It's both a comment and questions to the unicorn post/answer:

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

I prefer this answer over the others for it's simplicity and the fact that apparently some folks at Microsoft were consulted. I got three questions however and if they can be answered then I will call this answer the holy grail of all 404/500 error answers on the interwebs for an ASP.NET MVC (x) app.

@Pure.Krome

  1. Can you update your answer with the SEO stuff from the comments pointed out by GWB (there was never any mentioning of this in your answer) - <customErrors mode="On" redirectMode="ResponseRewrite"> and <httpErrors errorMode="Custom" existingResponse="Replace"> ?

  2. Can you ask your ASP.NET team friends if it is okay to do it like that - would be nice to have some confirmation - maybe it's a big no-no to change redirectMode and existingResponse in this way to be able to play nicely with SEO?!

  3. Can you add some clarification surrounding all that stuff ( customErrors redirectMode="ResponseRewrite" , customErrors redirectMode="ResponseRedirect" , httpErrors errorMode="Custom" existingResponse="Replace" , REMOVE customErrors COMPLETELY as someone suggested) after talking to your friends at Microsoft?

As I was saying; it would be supernice if we could make your answer more complete as this seem to be a fairly popular question with 54 000+ views.

Update : Unicorn answer does a 302 Found and a 200 OK and cannot be changed to only return 404 using a route. It has to be a physical file which is not very MVC:ish. So moving on to another solution. Too bad because this seemed to be the ultimate MVC:ish answer this far.


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

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 अलग-अलग मामले हैं कि एएसपी.नेट एमवीसी 3 ऐप्स 404 उत्पन्न कर सकते हैं।

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

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

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

(2) एक यूआरएल मार्ग तालिका में एक मैच पाता है, लेकिन एक अस्तित्व नियंत्रक निर्दिष्ट करता है।

(3) एक यूआरएल मार्ग तालिका में एक मैच पाता है, लेकिन एक अस्तित्वहीन कार्रवाई निर्दिष्ट करता है।

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

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

(5) एक कार्रवाई स्थिति कोड 404 के साथ एक HttpException फेंकता है।

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

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

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

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

(3) 302 पुनर्निर्देशन के बिना सीधे प्रतिक्रिया भेजें।

इसे पूरा करने के प्रयास करने के कई तरीके हैं:

(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. केवल आईआईएस 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. केवल आईआईएस 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. केवल आईआईएस 7+ पर काम करता है।
  2. उद्देश्य (2) स्वचालित रूप से पालन नहीं करता है। इसे मैन्युअल रूप से प्रोग्राम किया जाना चाहिए।
  3. मामलों (2), (3), (5) में उद्देश्य (3) का पालन नहीं करता है।

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


In MVC4 WebAPI 404 can be handle in the following way,

COURSES 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;
    }

HOME CONTROLLER

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

VIEW

<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>

GLOBAL

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 }
    );
}

परिणाम


It seems to me that the standard CustomErrors configuration should just work however, due to the reliance on Server.Transfer it seems that the internal implementation of ResponseRewrite isn't compatible with MVC.

This feels like a glaring functionality hole to me, so I decided to re-implement this feature using a HTTP module. The solution below allows you to handle any HTTP status code (including 404) by redirecting to any valid MVC route just as you would do normally.

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

This has been tested on the following platforms;

  • MVC4 in Integrated Pipeline Mode (IIS Express 8)
  • MVC4 in Classic Mode (VS Development Server, Cassini)
  • MVC4 in Classic Mode (IIS6)

लाभ

  • Generic solution which can be dropped into any MVC project
  • Enables support for traditional custom errors configuration
  • Works in both Integrated Pipeline and Classic modes

The Solution

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() {

        }


    }

}

प्रयोग

Include this as the final HTTP module in your web.config

  <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>

For those of you paying attention you will notice that in Integrated Pipeline mode this will always respond with HTTP 200 due to the way Server.TransferRequest works. To return the proper error code I use the following error controller.

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());
    }

}

1) Make abstract Controller class.

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) Make inheritence from this abstract class in your all controllers

public class HomeController : MyController
{}  

3) And add a view named "NotFound" in you View-Shared folder.


कोड http://blogs.microsoft.co.il/blogs/shay/archive/2009/03/06/real-world-error-hadnling-in-asp-net-mvc-rc2.aspx और कार्यों से लिया जाता है एएसपीनेट एमवीसी 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));
}

My shortened solution that works with unhandled areas, controllers and actions:

  1. Create a view 404.cshtml.

  2. Create a base class for your controllers:

    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. Create a custom controller factory returning your base controller as a fallback:

    public class ControllerFactory : DefaultControllerFactory
    {
        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            if (controllerType != null)
                return base.GetControllerInstance(requestContext, controllerType);
    
            return new Controller();
        }
    }
    
  4. Add to Application_Start() the following line:

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

मुझे वास्तव में कोट्टेक्स समाधान पसंद है और लगता है कि यह बहुत स्पष्ट रूप से समझाया गया है। मेरा एकमात्र जोड़ा चरण 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 जैसे यूआरएल के लिए


I went through most of the solutions posted on this thread. While this question might be old, it is still very applicable to new projects even now, so I spent quite a lot of time reading up on the answers presented here as well as else where.

As @Marco pointed out the different cases under which a 404 can happen, I checked the solution I compiled together against that list. In addition to his list of requirements, I also added one more.

  • The solution should be able to handle MVC as well as AJAX/WebAPI calls in the most appropriate manner. (ie if 404 happens in MVC, it should show the Not Found page and if 404 happens in WebAPI, it should not hijack the XML/JSON response so that the consuming Javascript can parse it easily).

This solution is 2 fold:

First part of it comes from @Guillaume at https://.com/a/27354140/2310818 . Their solution takes care of any 404 that were caused due to invalid route, invalid controller and invalid action.

The idea is to create a WebForm and then make it call the NotFound action of your MVC Errors Controller. It does all of this without any redirect so you will not see a single 302 in Fiddler. The original URL is also preserved, which makes this solution fantastic!

Second part of it comes from @Germán at https://.com/a/5536676/2310818 . Their solution takes care of any 404 returned by your actions in the form of HttpNotFoundResult() or throw new HttpException()!

The idea is to have a filter look at the response as well as the exception thrown by your MVC controllers and to call the appropriate action in your Errors Controller. Again this solution works without any redirect and the original url is preserved!

As you can see, both of these solutions together offer a very robust error handling mechanism and they achieve all the requirements listed by @Marco as well as my requirements. If you would like to see a working sample or a demo of this solution, please leave in the comments and I would be happy to put it together.


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

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

Install-Package MagicalUnicornMvcErrorToolkit -Version 1.0

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

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

और यह केवल आईआईएस 7 + और आईआईएस एक्सप्रेस के लिए है।

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

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

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

कुछ भी कस्टम करने की जरूरत नहीं है

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

चरण 1 -> दो स्थानों में अपना 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>

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

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

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

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

चरण 2 - ग्लोबल.एक्सएक्स में मार्ग बनाना

मेरा पूरा मार्ग अनुभाग यहाँ है ..

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 फ़ाइल के अंदर हैं, हम वैश्विक स्तर पर हैंडलरर विशेषता पंजीकृत नहीं करते हैं। नहीं, नहीं, नहीं सर। नड्डा। नहीं। निएन। नकारात्मक। 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 फ्रेमवर्क में निर्मित त्रुटियों को पहले से ही संभाल रहा है और हमने एक त्रुटि को संभालने के लिए हमें जो भी बकवास करने की आवश्यकता है उसे निर्दिष्ट किया है :) यह इस विधि में है!

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

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

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

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

बोनस टिप्पणियां

  • आपको Application_Error(object sender, EventArgs e) आवश्यकता नहीं है Application_Error(object sender, EventArgs e)
  • उपर्युक्त कदम सभी Elmah साथ 100% पूरी तरह से काम करते हैं। Elmah fraking wroxs!

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

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


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

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

  • मैं खराब कार्यों के साथ मिलान किए गए मार्गों को संभालना चाहता हूं
  • मैं खराब नियंत्रकों के साथ मिलान किए गए मार्गों को संभालना चाहता हूं
  • मैं अन-मिलान वाले मार्गों को नियंत्रित करना चाहता हूं (मनमानी यूआरएल जो मेरा ऐप समझ में नहीं आ रहा है) - मैं नहीं चाहता कि ये ग्लोबल.एक्सएक्स या आईआईएस तक बुलबुले हो जाएं क्योंकि तब मैं अपने एमवीसी ऐप में ठीक से रीडायरेक्ट नहीं कर सकता
  • मैं उपर्युक्त, कस्टम 404s जैसे ही संभालने का एक तरीका चाहता हूं - जैसे किसी ऑब्जेक्ट के लिए एक आईडी सबमिट की जाती है जो मौजूद नहीं है (शायद हटाया गया हो)
  • मैं चाहता हूं कि मेरे सभी 404 एमवीसी व्यू (एक स्थिर पृष्ठ नहीं) लौटाएं, जिसके लिए यदि आवश्यक हो तो मैं अधिक डेटा पंप कर सकता हूं ( codinghorror.com/blog/2007/03/… ) और उन्हें HTTP 404 स्टेटस कोड वापस करना होगा

उपाय

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

चरण 1: 404-त्रुटि तर्क के लिए एक आम जगह है

यह रखरखाव के लिए एक अच्छा विचार है। एक ErrorController उपयोग करें ताकि आपके codinghorror.com/blog/2007/03/… भविष्य में सुधार आसानी से अनुकूलित हो सकें। साथ ही, सुनिश्चित करें कि आपकी प्रतिक्रिया में 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

एएसपी.नेट एमवीसी में 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 एचटीपीएक्सप्शन को तार दें

ऐसा (यह स्ट्रक्चर मैप नहीं होना चाहिए):

एमवीसी 1.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;
    }
}

एमवीसी 2.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 हैंडलर को पसंद करता हूं।

404 के लिए यह दूसरा स्थान है।

चरण 4: ग्लोबल.एक्सएक्स को यूआरएल के लिए एक नोटफॉउंड रूट जोड़ें जो आपके ऐप में पार्स करने में विफल रहता है

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

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

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

चरण 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);
    }

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

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

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


I have gone through all articles but nothing works for me: My requirement user type anything in your url custom 404 page should show.I thought it is very straight forward.But you should understand handling of 404 properly:

 <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>

I found this article very helpfull.should be read at once. Custome error page-Ben Foster


Dealing with errors in ASP.NET MVC is just a pain in the butt. I tried a whole lot of suggestions on this page and on other questions and sites and nothing works good. One suggestion was to handle errors on web.config inside system.webserver but that just returns blank pages .

My goal when coming up with this solution was to;

  • NOT REDIRECT
  • Return PROPER STATUS CODES not 200/Ok like the default error handling

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

1 .Add the following to system.web section

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

The above handles any urls not handled by routes.config and unhandled exceptions especially those encountered on the views. Notice I used aspx not html . This is so I can add a response code on the code behind.

2 । Create a folder called Error (or whatever you prefer) at the root of your project and add the two webforms. Below is my 404 page;

<%@ 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>

And on the code behind I set the response code

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

Do the same for the 500 page

3 .To handle errors within the controllers. There's many ways to do it. इसी से मेरा काम बना है। All my controllers inherit from a base controller. In the base controller, I have the following methods

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 .Add the CustomError.cshtml to your Shared views folder. Below is mine;

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

Now in your application controller you can do something like this;

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();
    }
  }
}

Now for the caveat . It won't handle static file errors. So if you have a route such as example.com/widgets and the user changes it to example.com/widgets.html , they will get the IIS default error page so you have to handle IIS level errors some other way.


Try NotFoundMVC on nuget. It works , no setup.





http-status-code-404