C # MVC4 WebAPI ऐप के लिए मैं विश्व स्तर पर सभी अपवाद कैसे लॉग कर सकता हूं?


175

पृष्ठभूमि

मैं एक क्लाइंट के लिए एक एपीआई सर्विस लेयर विकसित कर रहा हूं और मुझसे विश्वभर की सभी त्रुटियों को पकड़ने और लॉग इन करने का अनुरोध किया गया है।

तो, जबकि एक अज्ञात समापन बिंदु (या कार्रवाई) की तरह कुछ ईएलएमएएच का उपयोग करके या इस तरह से कुछ जोड़कर आसानी से नियंत्रित किया जाता है Global.asax:

protected void Application_Error()
{
     Exception unhandledException = Server.GetLastError();
     //do more stuff
}

। । .unhandled त्रुटियाँ जो रूटिंग से संबंधित नहीं हैं, वे लॉग इन नहीं होती हैं। उदाहरण के लिए:

public class ReportController : ApiController
{
    public int test()
    {
        var foo = Convert.ToInt32("a");//Will throw error but isn't logged!!
        return foo;
    }
}

मैंने [HandleError]इस फ़िल्टर को पंजीकृत करके विश्व स्तर पर विशेषता स्थापित करने की कोशिश की है :

filters.Add(new HandleErrorAttribute());

लेकिन वह भी सभी त्रुटियों को लॉग नहीं करता है।

समस्या / प्रश्न

मैं /testऊपर कॉल करके उत्पन्न की गई त्रुटियों को कैसे रोक सकता हूं ताकि मैं उन्हें लॉग इन कर सकूं? ऐसा लगता है कि यह उत्तर स्पष्ट होना चाहिए, लेकिन मैंने वह सब कुछ करने की कोशिश की है जो मैं अब तक सोच सकता हूं।

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

यह संकल्प!

डारिन दिमित्रोव के लिए धन्यवाद, जिनके उत्तर को मैंने स्वीकार किया, मुझे यह पता चला। WebAPI करता है नियमित एमवीसी नियंत्रक की तरह त्रुटियों को संभालता नहीं है

यहाँ काम किया है:

1) अपने नाम स्थान पर एक कस्टम फ़िल्टर जोड़ें:

public class ExceptionHandlingAttribute : ExceptionFilterAttribute
{
    public override void OnException(HttpActionExecutedContext context)
    {
        if (context.Exception is BusinessException)
        {
            throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
            {
                Content = new StringContent(context.Exception.Message),
                ReasonPhrase = "Exception"
            });

        }

        //Log Critical errors
        Debug.WriteLine(context.Exception);

        throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
        {
            Content = new StringContent("An error occurred, please try again or contact the administrator."),
            ReasonPhrase = "Critical Exception"
        });
    }
}

2) अब WebApiConfig वर्ग में विश्व स्तर पर फ़िल्टर को पंजीकृत करें :

public static class WebApiConfig
{
     public static void Register(HttpConfiguration config)
     {
         config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{action}/{id}", new { id = RouteParameter.Optional });
         config.Filters.Add(new ExceptionHandlingAttribute());
     }
}

या आप पंजीकरण को छोड़ सकते हैं और केवल एक नियंत्रक को [ExceptionHandling]विशेषता के साथ सजा सकते हैं ।


मेरी भी यही समस्या है। अपवादित फ़िल्टर अपवाद को पकड़े जाने पर अपवाद फ़िल्टर विशेषता ठीक है, लेकिन जब मैं एक नया अपवाद फेंकता हूँ तो वह अपवाद फ़िल्टर विशेषता में नहीं पकड़ा जाता है, इस संबंध में कोई विचार?
daveBM

1
अज्ञात api कंट्रोलर कॉल जैसे myhost / api / undefinedapicontroller त्रुटियाँ अभी भी पकड़ में नहीं आई हैं। Application_error और Exception फ़िल्टर कोड निष्पादित नहीं किया गया है। उन्हें भी कैसे पकड़ा जाए?
एंड्रस

1
WebAPI v2.1 में वैश्विक त्रुटि हैंडलिंग जोड़ी गई थी। मेरी प्रतिक्रिया यहाँ देखें: stackoverflow.com/questions/17449400/…
DarrellNorton

1
यह कुछ परिस्थितियों में त्रुटियों को नहीं पकड़ेगा, जैसे "संसाधन नहीं मिला", या नियंत्रक निर्माता में त्रुटियां। : यहाँ देखें aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/Elmah/...
जॉर्डन मॉरिस

हे मैट। आपने उत्तर को प्रश्न के भाग के रूप में लिखा है लेकिन यह SO में एक सर्वोत्तम अभ्यास नहीं है। यहां उत्तर प्रश्न से अलग होना चाहिए। क्या आप यह लिख सकते हैं कि एक अलग उत्तर के रूप में (आप नीचे दिए गए "अपने खुद के प्रश्न का उत्तर दें" बटन का उपयोग कर सकते हैं)।
शशोअल्म

जवाबों:


56

यदि आपके वेब एपीआई को ASP.NET एप्लिकेशन के अंदर होस्ट किया गया है, तो Application_Errorआपके कोड में ईवेंट सभी गैर-अपवादित अपवादों के लिए कॉल किया जाएगा, जिसमें आपके द्वारा दिखाए गए परीक्षण कार्रवाई भी शामिल है। तो आपको बस इतना करना है कि Application_Error इवेंट के अंदर इस अपवाद को संभाल लें। नमूना कोड में आपने दिखाया है कि आप केवल अपवाद के प्रकार को संभाल रहे हैं HttpExceptionजो स्पष्ट रूप से Convert.ToInt32("a")कोड के साथ ऐसा नहीं है । इसलिए सुनिश्चित करें कि आप लॉग इन करें और वहां के सभी अपवादों को संभालें:

protected void Application_Error()
{
    Exception unhandledException = Server.GetLastError();
    HttpException httpException = unhandledException as HttpException;
    if (httpException == null)
    {
        Exception innerException = unhandledException.InnerException;
        httpException = innerException as HttpException;
    }

    if (httpException != null)
    {
        int httpCode = httpException.GetHttpCode();
        switch (httpCode)
        {
            case (int)HttpStatusCode.Unauthorized:
                Response.Redirect("/Http/Error401");
                break;

            // TODO: don't forget that here you have many other status codes to test 
            // and handle in addition to 401.
        }
        else
        {
            // It was not an HttpException. This will be executed for your test action.
            // Here you should log and handle this case. Use the unhandledException instance here
        }
    }
}

वेब एपीआई में अपवाद हैंडलिंग विभिन्न स्तरों पर किया जा सकता है। यहां detailed articleविभिन्न संभावनाओं की व्याख्या की गई है:

  • कस्टम अपवाद फ़िल्टर विशेषता जिसे वैश्विक अपवाद फ़िल्टर के रूप में पंजीकृत किया जा सकता है

    [AttributeUsage(AttributeTargets.All)]
    public class ExceptionHandlingAttribute : ExceptionFilterAttribute
    {
        public override void OnException(HttpActionExecutedContext context)
        {
            if (context.Exception is BusinessException)
            {
                throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
                {
                    Content = new StringContent(context.Exception.Message),
                    ReasonPhrase = "Exception"
                });
            }
    
            //Log Critical errors
            Debug.WriteLine(context.Exception);
    
            throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
            {
                Content = new StringContent("An error occurred, please try again or contact the administrator."),
                ReasonPhrase = "Critical Exception"
            });
        }
    }
  • कस्टम कार्रवाई चालान

    public class MyApiControllerActionInvoker : ApiControllerActionInvoker
    {
        public override Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
        {
            var result = base.InvokeActionAsync(actionContext, cancellationToken);
    
            if (result.Exception != null && result.Exception.GetBaseException() != null)
            {
                var baseException = result.Exception.GetBaseException();
    
                if (baseException is BusinessException)
                {
                    return Task.Run<HttpResponseMessage>(() => new HttpResponseMessage(HttpStatusCode.InternalServerError)
                    {
                        Content = new StringContent(baseException.Message),
                        ReasonPhrase = "Error"
    
                    });
                }
                else
                {
                    //Log critical error
                    Debug.WriteLine(baseException);
    
                    return Task.Run<HttpResponseMessage>(() => new HttpResponseMessage(HttpStatusCode.InternalServerError)
                    {
                        Content = new StringContent(baseException.Message),
                        ReasonPhrase = "Critical Error"
                    });
                }
            }
    
            return result;
        }
    }

काश यह इतना सरल होता, लेकिन त्रुटि अभी भी पकड़ में नहीं आ रही है। मैंने भ्रम से बचने के लिए सवाल अपडेट किया है। धन्यवाद।
मैट कैसहट

@MatthewPatrickCashatt, अगर यह अपवाद Application_Errorघटना में नहीं पकड़ा जा रहा है , इसका मतलब है कि कुछ अन्य कोड पहले इसका सेवन कर रहे हैं। उदाहरण के लिए, आपके पास कुछ कस्टम हैंडलेयर एट्रिब्यूट्स, कस्टम मॉड्यूल हो सकते हैं, ... अन्य स्थानों के गजिलियन हैं जहां अपवादों को पकड़ा और संभाला जा सकता है। लेकिन ऐसा करने के लिए सबसे अच्छा स्थान Application_Error इवेंट है, क्योंकि यही वह जगह है जहां सभी अपवादित अपवाद समाप्त होने जा रहे हैं।
डारिन दिमित्रोव

धन्यवाद फिर से, लेकिन कोई बात नहीं, /testउदाहरण हिट नहीं होता है। मैंने पहली पंक्ति पर एक ब्रेकपॉइंट लगाया है ( Exception unhandledException = . . .लेकिन /testपरिदृश्य में उस ब्रेकपॉइंट को हिट नहीं कर सकता । यदि मैं एक फर्जी url में डालता हूं, हालांकि, ब्रेकपॉइंट मारा जाता है।
मैट कशाट

1
@MatthewPatrickCashatt, आप पूरी तरह से सही हैं। Application_Errorघटना वेब एपीआई के लिए अपवाद को संभालने के लिए है क्योंकि यह सभी मामलों में ट्रिगर नहीं किया जाएगा सही जगह नहीं है। मैंने एक बहुत विस्तृत लेख प्राप्त किया है जिसे प्राप्त करने के लिए विभिन्न संभावनाओं की व्याख्या की गई है: weblogs.asp.net/fredriknormen/archive/2012/06/11/…
डारिन दिमित्रोव

1
@ डारिन दिमित्रोव अज्ञात एपीआई नियंत्रक कॉल जैसे मायहोस्ट / एपी / अपरिभाषित त्रुटियों को अभी भी नहीं पकड़ा गया है। Application_error और अपवाद फ़िल्टर कोड निष्पादित नहीं किया गया है। उन्हें भी कैसे पकड़ा जाए?
एंड्रस

79

पिछले उत्तरों के अतिरिक्त।

कल, ASP.NET वेब एपीआई 2.1 को न्यायिक रूप से जारी किया गया था
यह विश्व स्तर पर अपवादों को संभालने का एक और अवसर प्रदान करता है।
विवरण नमूने में दिए गए हैं ।

संक्षेप में, आप वैश्विक अपवाद लॉगर और / या वैश्विक अपवाद हैंडलर (केवल एक) जोड़ते हैं।
आप उन्हें कॉन्फ़िगरेशन में जोड़ें:

public static void Register(HttpConfiguration config)
{
  config.MapHttpAttributeRoutes();

  // There can be multiple exception loggers.
  // (By default, no exception loggers are registered.)
  config.Services.Add(typeof(IExceptionLogger), new ElmahExceptionLogger());

  // There must be exactly one exception handler.
  // (There is a default one that may be replaced.)
  config.Services.Replace(typeof(IExceptionHandler), new GenericTextExceptionHandler());
}

और उनका अहसास:

public class ElmahExceptionLogger : ExceptionLogger
{
  public override void Log(ExceptionLoggerContext context)
  {
    ...
  }
}

public class GenericTextExceptionHandler : ExceptionHandler
{
  public override void Handle(ExceptionHandlerContext context)
  {
    context.Result = new InternalServerErrorTextPlainResult(
      "An unhandled exception occurred; check the log for more information.",
      Encoding.UTF8,
      context.Request);
  }
}

2
यह पूरी तरह से काम किया। मैं लॉग इन करता हूं और समवर्ती रूप से संभालता हूं (क्योंकि मैं लॉगआईडी प्राप्त करता हूं और इसे वापस करता हूं ताकि उपयोगकर्ता कमेंटरी जोड़ सके), इसलिए मैं रिजल्ट को एक नया ResponseMessageResult पर सेट कर रहा हूं। यह थोड़ी देर के लिए मुझे गुस्सा दिला रहा है, धन्यवाद।
ब्रेट

8

रेथ्रो आदि क्यों? यह काम करता है और यह सेवा वापसी स्थिति 500 ​​आदि बना देगा

public class LogExceptionFilter : ExceptionFilterAttribute
{
    private static readonly ILog log = LogManager.GetLogger(typeof (LogExceptionFilter));

    public override void OnException(HttpActionExecutedContext actionExecutedContext)
    {
        log.Error("Unhandeled Exception", actionExecutedContext.Exception);
        base.OnException(actionExecutedContext);
    }
}

2

क्या आपने एक हैंडल एरर फ़िल्टर जैसे कुछ करने के बारे में सोचा है

[HandleError]
public class BaseController : Controller {...}

आप एक कस्टम संस्करण भी बना सकते हैं [HandleError]जिसके साथ आप त्रुटि जानकारी और लॉग करने के लिए अन्य सभी विवरण लिख सकते हैं


धन्यवाद, लेकिन मैंने पहले ही विश्व स्तर पर सेट कर दिया है। यह ऊपर के रूप में एक ही समस्या है, सभी त्रुटियों को लॉग नहीं किया जाता है।
मैट केसहट

1

एक कोशिश / पकड़ में पूरी बात लपेटें और बिना किसी अपवाद के लॉग इन करें, फिर इसे पास करें। जब तक ऐसा करने के लिए एक बेहतर अंतर्निहित तरीका नहीं है।

यहाँ एक संदर्भ है कैच ऑल (हैंडल्ड या अनहेल्ड) अपवाद

(संपादित करें: ओह एपीआई)


बस के मामले में, उसे अपवाद को फिर से उखाड़ फेंकना होगा।
दिगंबरारा

@DigCamara क्षमा करें, यही मेरा मतलब है कि इसे पास करके। फेंकना; उसे संभालना चाहिए। मैंने मूल रूप से कहा कि "यह तय करें कि बाहर निकलना है या फिर से लोड करना है", तब उन्हें एहसास हुआ कि यह एक एपीआई है। उस स्थिति में, एप्लिकेशन को यह तय करने के लिए कि उसे क्या करना है, यह बताने के लिए सबसे अच्छा है।
टिम

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