سؤال

أنا أبحث عن حل بسيط للقيام بتسجيل الاستثناءات مع معالجة الأخطاء في تطبيق ASP.Net MVC 1.0 الخاص بي.

لقد قرأت الكثير من المقالات، بما في ذلك الأسئلة المنشورة هنا على StackOverflow، والتي توفر جميعها حلولاً مختلفة لمواقف مختلفة.ما زلت غير قادر على التوصل إلى حل يناسب احتياجاتي.

وهنا متطلباتي:

  1. لكي أتمكن من استخدام السمة [HandleError] (أو ما يعادلها) في وحدة التحكم الخاصة بي، للتعامل مع جميع الاستثناءات التي يمكن طرحها من أي من الإجراءات أو طرق العرض.يجب أن يتعامل هذا مع كافة الاستثناءات التي لم تتم معالجتها بشكل محدد في أي من الإجراءات (كما هو موضح في النقطة 2).أود أن أكون قادرًا على تحديد العرض الذي يجب إعادة توجيه المستخدم إليه في حالات الخطأ، لجميع الإجراءات في وحدة التحكم.

  2. أريد أن أكون قادرًا على تحديد السمة [HandleError] (أو ما يعادلها) في الجزء العلوي من إجراءات محددة لالتقاط استثناءات محددة وإعادة توجيه المستخدمين إلى طريقة عرض مناسبة للاستثناء.يجب التعامل مع جميع الاستثناءات الأخرى بواسطة السمة [HandleError] الموجودة على وحدة التحكم.

  3. في كلتا الحالتين أعلاه، أريد أن يتم تسجيل الاستثناءات باستخدام log4net (أو أي مكتبة تسجيل أخرى).

كيف أتوجه نحو تحقيق ما سبق؟لقد قرأت عن جعل جميع وحدات التحكم الخاصة بي ترث من وحدة التحكم الأساسية التي تتجاوز طريقة OnException، حيث أقوم بالتسجيل.ومع ذلك، سيؤدي هذا إلى العبث بإعادة توجيه المستخدمين إلى طرق العرض المناسبة، أو سيجعل الأمر فوضويًا.

لقد قرأت عن كتابة إجراء التصفية الخاص بي والذي يطبق IExceptionFilter للتعامل مع هذا، ولكن هذا سوف يتعارض مع السمة [HandleError].

حتى الآن، أفكاري هي أن الحل الأفضل هو كتابة السمة الخاصة بي التي ترث من HandleErrorAttribute.بهذه الطريقة أحصل على جميع وظائف [HandleError]، ويمكنني إضافة تسجيل log4net الخاص بي.الحل هو كما يلي:

    public class HandleErrorsAttribute: HandleErrorAttribute {

      private log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

      public override void OnException(ExceptionContext filterContext)
      {
          if (filterContext.Exception != null)
          {
            log.Error("Error in Controller", filterContext.Exception);
          }

          base.OnException(filterContext);
      }
   }

هل سيعمل الكود أعلاه مع متطلباتي؟إذا لم يكن الأمر كذلك، ما هو الحل الذي يلبي متطلباتي؟

هل كانت مفيدة؟

المحلول

ما زلت في حيرة من أمري بشأن جميع الحلول المختلفة المتوفرة، وكيف يمكن أن تتداخل السمات مع بعضها البعض، لكنني اخترت هذا الحل:

public class LogErrorsAttribute: FilterAttribute, IExceptionFilter
{
    #region IExceptionFilter Members

    void IExceptionFilter.OnException(ExceptionContext filterContext)
    {
        if (filterContext != null && filterContext.Exception != null)
        {
            string controller = filterContext.RouteData.Values["controller"].ToString();
            string action = filterContext.RouteData.Values["action"].ToString();
            string loggerName = string.Format("{0}Controller.{1}", controller, action);

            log4net.LogManager.GetLogger(loggerName).Error(string.Empty, filterContext.Exception);
        }

    }

    #endregion
}

ما زلت أستخدم السمة [HandleError] كما هو موضح في السؤال الأصلي، وأقوم فقط بتزيين كل وحدة تحكم بسمة [LogErrors].

يناسبني هذا، لأنه يحافظ على تسجيل الأخطاء في مكان واحد ولا يتسبب في تسجيل الاستثناءات المكررة عدة مرات (وهو ما سيحدث إذا قمت بتوسيع [HandleError] واستخدمت السمة في أماكن متعددة).

لا أعتقد أنه سيكون من الممكن دمج كل من تسجيل الاستثناءات ومعالجة الأخطاء في سمة أو فئة واحدة، دون أن يصبح الأمر مملاً ومعقدًا للغاية، أو يؤثر على استخدام [HandleError]

لكن هذا يناسبني لأنني أقوم بتزيين كل وحدة تحكم مرة واحدة فقط، باستخدام السمة [LogErrors]، وتزيين وحدات التحكم والإجراءات باستخدام [HandleError] تمامًا كما أريد، دون أن تتداخل مع بعضها البعض.

تحديث:

فيما يلي مثال لكيفية استخدامه:

[LogErrors(Order = 0)]
[HandleError(Order = 99)]
public class ContactController : Controller
{
    public ActionResult Index()
    {
        return View(Views.Index);
    }

    public ActionResult Directions()
    {
        return View(Views.Directions);
    }


    public ActionResult ContactForm()
    {
        FormContactMessage formContactMessage = new FormContactMessage();

        return View(Views.ContactForm,formContactMessage);
    }

    [HandleError(ExceptionType = typeof(SmtpException), View = "MessageFailed", Order = 1)]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult ContactForm(FormContactMessage formContactMessage)
    {
        if (ModelState.IsValid)
        {
            if (formContactMessage.IsValid)
            {
                SmtpClient client = new SmtpClient();

                MailAddress recipientAddress = new MailAddress(Properties.Settings.Default.ContactFormRecipientEmailAddress);
                MailAddress senderAddress = new MailAddress(Properties.Settings.Default.ContactFormSenderEmailAddress);
                MailMessage mailMessage = formContactMessage.ToMailMessage(recipientAddress, senderAddress);

                client.Send(mailMessage);

                return View("MessageSent");
            }
            else
            {
                ModelState.AddRuleViolations(formContactMessage.GetRuleViolations());
            }
        }
        return View(Views.ContactForm, formContactMessage);
    }

    private static class Views
    {
        public static string Index { get { return "Index"; } }
        public static string Directions { get { return "Directions"; } }
        public static string ContactForm { get { return "ContactForm"; } }

    }
}

في الكود أعلاه، SmtpExceptions في ملف ContactForm تتم معالجة التحميل الزائد للإجراء بطريقة محددة للغاية - حيث يتم تقديم صفحة عرض للمستخدم خاصة بالرسائل المرسلة الفاشلة، وفي هذه الحالة تسمى "MessageFailed".تتم معالجة كافة الاستثناءات الأخرى من خلال السلوك الافتراضي لـ [HandleError].لاحظ أيضًا أن تسجيل الأخطاء يحدث أولاً، متبوعًا بمعالجة الأخطاء.ويدل على ذلك ما يلي:

[LogErrors(Order = 0)]
[HandleError(Order = 99)]

تحديث:

هناك حل بديل لهذا، مع شرح جيد جدا.أوصي بقراءته للحصول على فهم أفضل للقضايا المعنية.

سمة ASP.NET MVC HandleError وصفحات الأخطاء المخصصة واستثناءات التسجيل(شكرًا لسكوت شيبرد أدناه، الذي قدم الرابط في الإجابة أدناه).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top