
إذا كنت من مطوري الواجهة الخلفية c # ، فربما تحتاج عاجلاً أم آجلاً إلى إيجاد طريقة موحدة للتعامل مع المواقف الاستثنائية. رغم أنه ، حتى إذا كنت راضياً عن رمز 500 في الإجابة ، فإن هذه المقالة ستظل تساعد في تحسين طريقتك ، مع عدم فرض أي شيء على إعادة الكتابة.
سنتحدث عن مكتبة ASP.NET ، والتي تتيح لك حل هذه المشكلة بأناقة قدر الإمكان. بالنسبة لأولئك الذين هم كسولون جدًا في قراءة مقال طويل - التمهيدي والمكتبة نفسها
هنا ، مثال على ذلك. متاح على nuget.org وسأكون سعيدًا فقط إذا كان سيفيد أي شخص. وهكذا ، دعنا ننتقل إلى الكود. أولاً ، دعونا نلقي نظرة على البدائل.
واحدة من أول الأشياء التي قد تتبادر إلى الذهن هي إنشاء DTO (كائن نقل البيانات) لمعالجة الاستثناءات ، والتقاط استثناء في وحدة التحكم (على الرغم من أنه ليس من الضروري أن يكون استثناءً ، فمن الممكن فقط التحقق من وجود قيمة خالية أو شيء من هذا القبيل) ، املأ البيانات الموجودة في DTO وأرسلها إلى العميل. قد يبدو رمز هذه الطريقة كالتالي:
public IActionResult Get() { try {
خيار آخر هو استخدام رموز حالة HTTP لهذا الغرض.
public IActionResult Get() { try {
ممارسة شائعة إلى حد ما ، ولكن لها عيوبها: قد يكون من الصعب وصف جوهر الموقف الخاص بك باستخدام أحد الرموز القياسية ، وهذا هو السبب في أنه يمكن تفسير نفس الرمز بشكل مختلف حتى على نفس النظام ، كما أنه يوفر معلومات قليلة جدًا للتصحيح إلى المطور.
وهنا قد يبدأ البعض في الجمع بين هاتين الطريقتين ، وبنسب مختلفة. في مكان ما سوف ينسون إرسال DTO ، في مكان ما لن يتم إرسال الكود أو سيتم إرسال الكود غير الصحيح ، ولكن في مكان ما بشكل عام سيتم إجراء تسلسل مع إعدادات json الخاطئة ولن يعودوا ما هو مطلوب.
في مواجهة ما سبق ، يحاول الكثيرون حل هذه المشكلة باستخدام
app.UseExceptionHandler ()؛ عن طريق التعامل مع استثناءات من خلال ذلك. هذه محاولة جيدة ، ولكنها لن تتيح لك نسيان المشكلة بسهولة. أولاً ، ستظل تواجه مشكلة اختيار DTO للاستثناءات. ثانياً ، لن يسمح معالج مثل بمعالجة رموز خطأ http التي تم إرجاعها من وحدات التحكم ، لأن استثناء لم يحدث. ثالثًا ، وبهذه الطريقة من غير المناسب حل مشكلة تصنيف الأخطاء ، يجب عليك كتابة الكثير من التعليمات البرمجية لإرفاق رسالة أو رمز http أو شيء ما لكل استثناء. ورابعًا ، تفقد فرصة استخدام AspA DeveloperExceptionPage ، وهو غير مريح للغاية للتصحيح. حتى إذا قمت بحل هذه المشكلة بطريقة أو بأخرى ، فسيتعين على جميع المطورين في هذا المشروع اتباع المواصفات بدقة ، وبناء خطأ في التعامل مع الاستثناءات ، وعدم إرجاع DTO ، وإلا قد تبدو الأخطاء في api مختلفة عن طريقة لأخرى.
استثناء خيار معالجة الاستثناء
قبل أن أظهر كيف يتيح لك IRO.Mvc.MvcExceptionHandler معالجة الاستثناءات ، أولاً سأصف كيف أرى معالجة الاستثناء المثالية. للقيام بذلك ، نقوم بتأسيس عدد من المتطلبات:
- يجب أن يكون DTO ، لكننا أيضًا لا نرفض رموز http ، لأن بالنسبة للعديد من الأخطاء ، فهي لا تزال مناسبة تمامًا ، ويمكن استخدامها في كل مكان وفي مشروع قديم يتعين عليك دعمه أيضًا ، وهي ببساطة عالمية. سيتضمن DTO القياسي حقل IsError (الذي يسمح بالكتابة بمعالجة الأخطاء عالمياً على العميل) ، كما يجب أن يحتوي على رمز خطأ سلسلة ErrorKey ، والذي يمكن للمطور التعرف عليه فورًا فقط من خلال النظر إليه والذي يوفر مزيدًا من المعلومات. بالإضافة إلى ذلك ، يمكنك إضافة رابط إلى صفحة مع وصف لهذا الخطأ ، إذا لزم الأمر.
- هذا هو كل شيء في همز. في وضع التطوير ، يجب على DTO إرجاع تتبع مكدس ، طلب البيانات: ملفات تعريف الارتباط ، الرؤوس ، المعلمات. إذا نظرنا إلى الأمام ، ترجع الوسيطة الموضحة في المقالة ارتباطًا إلى DeveloperExceptionPage الذي تم إنشاؤه ، والذي يسمح لك بمشاهدة استثناء الاستثناء في نموذج مناسب ، لكن المزيد حول هذا لاحقًا.
- يمكن للمطور ربط الاستثناء ورمز خطأ http و ErrorKey. هذا يعني أنه في حالة إرسال رمز 403 من وحدة التحكم ، إذا قام المطور بإرفاق ErrorKey معين به ، فسيتم إرجاع DTO الذي يحتوي عليه. والعكس بالعكس ، في حالة حدوث UnauthorizedAccessException ، فسيتم ربطه برمز http و ErrorKey.
هذا هو التنسيق الافتراضي المستخدم في المكتبة:
{ "__IsError": true, "ErrorKey": "ClientException", "InfoUrl": "https://iro.com/errors/ClientException" }
يجب أن أقول على الفور أن النموذج الذي سيتم نقل البيانات به إلى العميل يمكن أن يكون على الإطلاق ، وهذا مجرد خيار من الخيارات.
IRO.Mvc.MvcExceptionHandler
الآن سأبين كيف حللت هذه المشكلة بنفسي عن طريق كتابة مكتبة IRO.Mvc.MvcExceptionHandler.
نقوم بتوصيل معالج استثناء تمامًا مثل أي برنامج وسيط آخر - في فئة بدء التشغيل.
app.UseMvcExceptionHandler((s) => {
داخل المفوض الذي يتم تفويضه ، نحتاج إلى تهيئة البرامج الوسيطة الخاصة بنا. من الضروري تعيين استثناءات (ربط) لرموز http و ErrorKey. أدناه هو أسهل خيار الإعداد.
s.Mapping((builder) => { builder.RegisterAllAssignable<Exception>( httpCode: 500, errorKeyPrefix: "Ex_" ); });
كما وعدت للمطورين المتشددين الأكثر
كسولًا الذين لم يعتادوا على التعامل مع الاستثناءات - لا ينبغي القيام بأي شيء آخر. سيقوم هذا الرمز بربط جميع الاستثناءات في خط أنابيب ASP.NET بـ DTO الشائعة بالرمز 500 ، وسيتم كتابة اسم الاستثناء إلى ErrorKey.
تجدر الإشارة إلى أن طريقة RegisterAllAssignable لا تسجل استثناءًا من النوع المحدد فحسب ، بل تسجل أيضًا جميع أحفاده أيضًا. إذا كنت ترغب في إرسال معلومات فقط عن استثناءات محددة إلى العميل ، فهذا قرار معقول تمامًا لإنشاء ClientException وتعيينه فقط. في الوقت نفسه ، إذا قمت بتعيين رمز http واحد لـ ClientException ، وقمت بتعيين رمز آخر لخلفه SpecialClientException ، فسيتم استخدام الرمز SpecialClientException لجميع أحفاده ، مع تجاهل إعداد ClientException. كل هذا مخبأ ، لذلك لن تكون هناك مشكلات في الأداء.
يمكنك صقل وتسجيل رمز ErrorKey و http الخاص بك لاستثناء محدد:
s.Mapping((builder) => {
بالإضافة إلى التعيين ، من المفيد تكوين الأوزان الوسطى. يمكنك تحديد إعدادات تسلسل json ، وعنوان موقعك ، ورابط لصفحة وصف الخطأ ، وطريقة تشغيل البرنامج الوسيط من خلال IsDebug ، رمز http القياسي للاستثناءات غير المعالجة.
s.ErrorDescriptionUrlHandler = new FormattedErrorDescriptionUrlHandler("https://iro.com/errors/{0}"); s.IsDebug = isDebug; s.DefaultHttpCode = 500; s.JsonSerializerSettings.Formatting = Formatting.Indented; s.Host="https://iro.com"; s.CanBindByHttpCode = true;
تشير الخاصية الأخيرة إلى ما إذا كان من الممكن ربط DTO الخاص بنا برمز http.
يمكنك أيضًا تحديد كيفية التعامل مع المواقف مع الاستثناءات الداخلية ، على سبيل المثال ، TaskCanceledException مع وجود خطأ داخلي مسجل بسبب .Wait (). على سبيل المثال ، فيما يلي محلل قياسي يستخرج الاستثناءات الداخلية من هذه الاستثناءات ويعمل معها بالفعل:
s.InnerExceptionsResolver = InnerExceptionsResolvers.InspectAggregateException;
إذا كنت بحاجة إلى ضبط التسلسل ، فيمكنك تعيين أسلوب FilterAfterDTO. العودة الحقيقية لتعطيل المعالجة القياسية وتسلسل errorContext.ErrorDTO كما تريد. هناك حق الوصول إلى HttpContext والخطأ نفسه.
s.FilterAfterDTO = async (errorContext) => {
DeveloperExceptionPage ومزايا أخرى لوضع التصحيح
لقد اكتشفنا الإعدادات ، والآن ، دعونا نتعرف على كيفية تصحيح كل هذه الأخطاء. في اختبار DTO ، كانت الإجابة في الإجابة بسيطة وأظهرتها بالفعل أعلاه ، والآن سأظهر كيف يبدو نفس DTO في وضع التصحيح:

كما ترون ، هناك الكثير من المعلومات هنا ، وهناك بيانات stackrace وطلب. لكن الأمر أكثر ملاءمة لمجرد اتباع الرابط في حقل DebugUrl وعرض بيانات الخطأ دون الضغط:

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