دليل رائع حول كيفية إنشاء واجهات برمجة التطبيقات RESTful باستخدام ASP.NET Core

دليل خطوة بخطوة حول كيفية تنفيذ واجهات برمجة تطبيقات RESTful النظيفة والقابلة للصيانة

صورة لجيفرسون سانتوس ، نُشرت في Unsplash

نظرة عامة

الراحة ليست مصطلح جديد. يشير إلى النمط المعماري حيث تتلقى خدمات الويب البيانات وترسلها من وإلى تطبيقات العميل. الهدف من هذه التطبيقات هو تركيز البيانات التي ستستخدمها تطبيقات العملاء المختلفة.

يعد اختيار الأدوات المناسبة لكتابة خدمات RESTful أمرًا بالغ الأهمية نظرًا لأننا نحتاج إلى الاهتمام بالتدرج والصيانة والتوثيق وكافة الجوانب الأخرى ذات الصلة. يوفر لنا ASP.NET Core واجهة برمجة تطبيقات قوية وسهلة الاستخدام تعتبر رائعة لتحقيق هذه الأهداف.

في هذه المقالة ، سأوضح لك كيفية كتابة واجهة برمجة تطبيقات RESTful منظمة جيدًا لسيناريو حقيقي "تقريبًا" ، باستخدام إطار عمل ASP.NET Core. سأقوم بتفصيل الأنماط والاستراتيجيات الشائعة لتبسيط عملية التطوير.

سأوضح لك أيضًا كيفية دمج الأُطر والمكتبات العامة ، مثل Entity Framework Core و AutoMapper ، لتوفير الوظائف اللازمة.

المتطلبات الأساسية

أتوقع أن تكون لديك معرفة بمفاهيم البرمجة الموجهة للكائنات.

على الرغم من أنني سأغطي تفاصيل كثيرة عن لغة البرمجة C # ، إلا أنني أوصيك أن تكون لديك معرفة أساسية بهذا الموضوع.

أفترض أيضًا أنك تعرف ماهية REST ، وكيف يعمل بروتوكول HTTP ، وما هي نقاط النهاية لواجهة برمجة التطبيقات وما هو JSON. فيما يلي برنامج تعليمي رائع حول هذا الموضوع. الشرط الأخير هو أن تفهم كيف تعمل قواعد البيانات العلائقية.

للترميز معي ، سيتعين عليك تثبيت .NET Core 2.2 ، وكذلك Postman ، الأداة التي سأستخدمها لاختبار واجهة برمجة التطبيقات. أنصحك باستخدام محرر رمز مثل Visual Studio Code لتطوير API. اختر محرر الكود الذي تفضله. إذا اخترت محرر الرمز هذا ، فإنني أوصيك بتثبيت ملحق C # للحصول على تمييز أفضل للرمز.

يمكنك العثور على رابط إلى مستودع جيثب لواجهة برمجة التطبيقات في نهاية هذه المقالة ، للتحقق من النتيجة النهائية.

نطاق

دعنا نكتب واجهة برمجة تطبيقات الويب الخيالية لسوبر ماركت. دعونا نتخيل أنه يتعين علينا تنفيذ النطاق التالي:

  • قم بإنشاء خدمة RESTful تتيح لتطبيقات العميل إدارة كتالوج منتجات السوبر ماركت. تحتاج إلى كشف نقاط النهاية لإنشاء وقراءة وتعديل وحذف فئات المنتجات ، مثل منتجات الألبان ومستحضرات التجميل ، وكذلك لإدارة منتجات هذه الفئات.
  • بالنسبة للفئات ، نحتاج إلى تخزين أسمائهم. بالنسبة للمنتجات ، نحتاج إلى تخزين أسمائهم ووحدة القياس (على سبيل المثال ، KG للمنتجات المقاسة بالوزن) ، والكمية الموجودة في العبوة (على سبيل المثال ، 10 إذا كان المنتج عبارة عن حزمة من البسكويت) وفئاتها المعنية.

لتبسيط المثال ، لن أتعامل مع المنتجات في المخزون وشحن المنتج والأمن وأي وظائف أخرى. النطاق المعطى يكفي لإظهار كيفية عمل ASP.NET Core.

لتطوير هذه الخدمة ، نحتاج أساسًا إلى نقطتي واجهة API: واحدة لإدارة الفئات وواحدة لإدارة المنتجات. فيما يتعلق باتصالات JSON ، يمكننا التفكير في الردود على النحو التالي:

نقطة نهاية API: / api / Categories

استجابة JSON (لطلبات GET):

{
  [
    {"id": 1 ، "name": "الفواكه والخضروات"} ،
    {"id": 2 ، "name": "Breads"} ،
    ... // فئات أخرى
  ]
}

نقطة نهاية واجهة برمجة التطبيقات: / api / products

استجابة JSON (لطلبات GET):

{
  [
    {
      "معرف": 1 ،
      "الاسم": "السكر" ،
      "كميةحزمة": 1 ،
      "unitOfMeasurement": "KG"
      "الفئة": {
        "معرف": 3 ،
        "الاسم": "السكر"
      }
    }،
    … // منتجات اخرى
  ]
}

لنبدأ بكتابة التطبيق.

الخطوة 1 - إنشاء API

بادئ ذي بدء ، يتعين علينا إنشاء بنية المجلدات لخدمة الويب ، ثم يتعين علينا استخدام أدوات .NET CLI لسقطة واجهة برمجة تطبيقات الويب الأساسية. افتح موجه الأوامر أو موجه الأوامر (يعتمد على نظام التشغيل الذي تستخدمه) واكتب الأوامر التالية بالتسلسل:

mkdir src / Supermarket.API
مؤتمر نزع السلاح src / سوبر ماركت
dotnet جديد webapi

الأمرين الأولين ببساطة إنشاء دليل جديد ل API وتغيير الموقع الحالي إلى المجلد الجديد. ينشئ آخر مشروع جديد يتبع قالب واجهة برمجة تطبيقات الويب ، وهذا هو نوع التطبيق الذي نقوم بتطويره. يمكنك قراءة المزيد حول هذه الأوامر وقوالب المشاريع الأخرى التي يمكنك إنشاء التحقق من هذا الارتباط.

سيكون لدى الدليل الجديد الآن البنية التالية:

هيكل المشروع

نظرة عامة على الهيكل

يتكون تطبيق ASP.NET Core من مجموعة من البرامج الوسيطة (أجزاء صغيرة من التطبيق متصلة بخط أنابيب التطبيق ، والتي تتعامل مع الطلبات والاستجابات) التي تم تكوينها في فئة بدء التشغيل. إذا كنت قد عملت بالفعل مع أطر عمل مثل Express.js من قبل ، فهذا المفهوم ليس جديدًا عليك.

عند بدء تشغيل التطبيق ، يتم استدعاء الطريقة الرئيسية ، من فئة البرنامج. يقوم بإنشاء مضيف ويب افتراضي باستخدام تكوين بدء التشغيل ، ويعرض التطبيق عبر HTTP من خلال منفذ معين (افتراضيًا ، المنفذ 5000 لـ HTTP و 5001 لـ HTTPS).

ألق نظرة على فئة ValuesController داخل المجلد Controllers. يعرض الطرق التي سيتم استدعاؤها عندما يتلقى API طلبات من خلال المسار / api / القيم.

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

الخطوة 2 - إنشاء نماذج المجال

سأطبق بعض مفاهيم التصميم التي ستحافظ على التطبيق بسيطًا وسهل الصيانة.

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

wtf - قياس جودة الكود بواسطة smitty42 مرخص بموجب CC-BY-ND 2.0

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

داخل الدليل Supermarket.API ، قم بإنشاء مجلد جديد يسمى المجال. داخل مجلد المجال الجديد ، قم بإنشاء مجلد آخر يسمى الطرازات. النموذج الأول الذي يتعين علينا إضافته إلى هذا المجلد هو الفئة. في البداية ، ستكون فئة كائن CLR قديم عادي (POCO) بسيطة. هذا يعني أن الفصل سيكون له خصائص لوصف معلوماته الأساسية فقط.

الفئة لها خاصية معرف ، لتحديد الفئة ، و Nameproperty. لدينا أيضا خاصية المنتجات. سيتم استخدام هذا الأخير بواسطة Entity Framework Core ، ومعظم تطبيقات ASP.NET Core التي تستخدمها ORM لاستمرار البيانات في قاعدة البيانات ، لرسم خريطة للعلاقة بين الفئات والمنتجات. كما أنه من المنطقي التفكير فيما يتعلق بالبرمجة الموجهة للكائنات ، لأن الفئة بها العديد من المنتجات ذات الصلة.

لدينا أيضا لإنشاء نموذج المنتج. في نفس المجلد ، أضف فئة منتج جديدة.

يحتوي المنتج أيضًا على خصائص المعرف والاسم. وهي أيضًا خاصية QuantityInPackage ، والتي تخبر عدد وحدات المنتج التي لدينا في حزمة واحدة (تذكر مثال البسكويت لنطاق التطبيق) وخاصية UnitOfMeasurement. ويمثل هذا النوع بنوع التعداد ، الذي يمثل تعداد وحدات القياس الممكنة. سيتم استخدام الخصائص الأخيرة اثنين ، CategoryId والفئة من قبل ORM لتعيين العلاقة بين المنتجات والفئات. يشير إلى أن المنتج لديه فئة واحدة وفئة واحدة فقط.

دعونا نحدد الجزء الأخير من نماذج النطاق لدينا ، وهو تعداد EUnitOfMeasurement.

حسب الاصطلاح ، لا تحتاج التعدادات إلى البدء بحرف "E" أمام أسمائها ، ولكن في بعض المكتبات والأطر ستجد هذه البادئة كوسيلة لتمييز التعدادات عن الواجهات والفئات.

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

لاحظ سمة الوصف المطبقة على كل احتمال التعداد. السمة هي طريقة لتعريف البيانات الأولية عبر الفئات والواجهات والخصائص والمكونات الأخرى للغة C #. في هذه الحالة ، سوف نستخدمها لتبسيط الاستجابات لنقطة نهاية واجهة برمجة التطبيقات للمنتجات ، ولكن لا داعي للقلق بها الآن. سوف نعود إلى هنا لاحقًا.

النماذج الأساسية لدينا جاهزة للاستخدام. الآن يمكننا البدء في كتابة نقطة نهاية واجهة برمجة التطبيقات لإدارة جميع الفئات.

الخطوة 3 - API الفئات

في المجلد Controllers ، أضف فئة جديدة تسمى CategoriesController.

وفقًا للاتفاقية ، ستصبح جميع الفئات الموجودة في هذا المجلد والتي تنتهي بـ "وحدة التحكم" لاحقة تحكم في تطبيقنا. وهذا يعني أنهم ذاهبون للتعامل مع الطلبات والردود. يجب أن ترث هذه الفئة من فئة وحدة التحكم ، المعرفة في مساحة الاسم Microsoft.AspNetCore.Mvc.

تتكون مساحة الاسم من مجموعة من الفئات والواجهات والتعدادات والبنيات ذات الصلة. يمكنك التفكير في الأمر كشيء مشابه لوحدات لغة جافا سكريبت أو حزم من Java.

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

لنبدأ بمعالجة طلبات GET. أولاً وقبل كل شيء ، عندما يطلب شخص ما بيانات من / api / Categories عبر فعل GET ، يحتاج واجهة برمجة التطبيقات إلى إرجاع جميع الفئات. يمكننا إنشاء خدمة فئة لهذا الغرض.

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

باستخدام الخدمات ، يمكننا عزل الطلب ومعالجة الاستجابة عن المنطق الحقيقي المطلوب لإكمال المهام.

الخدمة التي سننشئها في البداية ستحدد سلوكًا منفردًا أو طريقة واحدة: طريقة سرد. نتوقع أن تقوم هذه الطريقة بإرجاع جميع الفئات الموجودة في قاعدة البيانات.

للبساطة ، لن نتعامل مع ترقيم الصفحات أو التصفية في هذه الحالة. سأكتب مقالًا في المستقبل يوضح كيفية التعامل بسهولة مع هذه الميزات.

لتعريف السلوك المتوقع لشيء ما في C # (ولغات أخرى موجهة للكائنات ، مثل Java ، على سبيل المثال) ، نقوم بتعريف واجهة. توضح الواجهة كيفية عمل شيء ما ، لكنها لا تنفذ المنطق الحقيقي للسلوك. يتم تطبيق المنطق في الفصول التي تقوم بتطبيق الواجهة. إذا لم يكن هذا المفهوم واضحًا بالنسبة لك ، فلا تقلق. ستفهم ذلك منذ فترة.

داخل مجلد المجال ، قم بإنشاء دليل جديد يسمى الخدمات. هناك ، إضافة واجهة تسمى ICategoryService. حسب الاصطلاح ، يجب أن تبدأ جميع الواجهات بالحرف الكبير "I" في C #. حدد رمز الواجهة كما يلي:

يجب أن ترجع تطبيقات أسلوب ListAsync بشكل غير متزامن تعداد الفئات.

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

لدينا الكثير من الاتفاقيات ، أليس كذلك؟ أنا شخصياً أحب ذلك ، لأنه يحافظ على سهولة قراءة التطبيقات ، حتى لو كنت جديدًا على شركة تستخدم تقنية .NET.

"- حسنًا ، لقد حددنا هذه الواجهة ، لكنها لا تفعل شيئًا. كيف يمكن أن تكون مفيدة؟ "

إذا كنت من لغة مثل Javascript أو لغة أخرى غير مكتوبة بقوة ، فقد يبدو هذا المفهوم غريبًا.

تسمح لنا الواجهات باستخلاص السلوك المطلوب من التنفيذ الحقيقي. باستخدام آلية تُعرف باسم حقن التبعية ، يمكننا تنفيذ هذه الواجهات وعزلها عن المكونات الأخرى.

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

"- يبدو مربكا حقا. ألا يمكننا ببساطة إنشاء فصل يقوم بهذه الأشياء بالنسبة لنا؟ "

دعنا نواصل تنفيذ API الخاصة بنا وسوف تفهم سبب استخدام هذا النهج.

قم بتغيير رمز CategoriesController كما يلي:

لقد قمت بتحديد وظيفة مُنشئ لوحدة التحكم الخاصة بنا (يتم استدعاء المُنشئ عند إنشاء مثيل جديد لفئة) ، ويتلقى مثيلًا من فئة ICategoryService. وهذا يعني أن المثيل يمكن أن يكون أي شيء ينفذ واجهة الخدمة. أقوم بتخزين هذا المثيل في حقل خاص للقراءة فقط _categoryService. سنستخدم هذا الحقل للوصول إلى أساليب تنفيذ خدمة الفئات الخاصة بنا.

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

أسفل المُنشئ ، قمت بتحديد الطريقة التي ستقوم بمعالجة طلبات / api / الفئات. تخبر سمة HttpGet خط أنابيب ASP.NET Core باستخدامه للتعامل مع طلبات GET (يمكن حذف هذه السمة ، لكن من الأفضل كتابتها لسهولة القراءة).

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

حسنًا ، لقد حددنا البنية الأولية لواجهة برمجة التطبيقات لدينا. الآن ، من الضروري تطبيق خدمة الفئات حقًا.

الخطوة 4 - تنفيذ خدمة الفئات

في المجلد الجذر لواجهة برمجة التطبيقات (المجلد Supermarket.API) ، قم بإنشاء واحد جديد يسمى الخدمات. سنضع جميع تطبيقات الخدمات هنا. داخل المجلد الجديد ، أضف فئة جديدة تسمى CategoryService. قم بتغيير الكود كما يلي:

إنها ببساطة الكود الأساسي لتطبيق الواجهة ، لكننا لا نزال لا نتعامل مع أي منطق. دعونا نفكر في كيفية عمل طريقة الإدراج.

نحتاج إلى الوصول إلى قاعدة البيانات وإعادة جميع الفئات ، ثم نحتاج إلى إعادة هذه البيانات إلى العميل.

فئة الخدمة ليست فئة يجب أن تتعامل مع الوصول إلى البيانات. يوجد نمط يسمى "نمط السجل" يُستخدم لإدارة البيانات من قواعد البيانات.

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

تحتاج خدمتنا إلى التحدث إلى مستودع الفئة ، للحصول على قائمة الكائنات.

من الناحية النظرية ، يمكن للخدمة "التحدث" إلى مستودع أو أكثر أو خدمات أخرى لأداء العمليات.

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

لنقم بإنشاء مستودع يكون مسؤولاً عن الوساطة في اتصال قاعدة البيانات كوسيلة لاستمرار الفئات.

الخطوة 5 - مستودع الفئات وطبقة الثبات

داخل مجلد المجال ، قم بإنشاء دليل جديد يسمى المستودعات. ثم قم بإضافة واجهة جديدة تسمى ICategoryRespository. حدد الواجهة على النحو التالي:

الرمز الأولي مطابق بشكل أساسي لرمز واجهة الخدمة.

بعد تعريف الواجهة ، يمكننا العودة إلى فئة الخدمة والانتهاء من تنفيذ طريقة الإدراج ، وذلك باستخدام مثيل ICategoryRepository لإرجاع البيانات.

الآن علينا أن ننفذ المنطق الحقيقي لمستودع الفئة. قبل القيام بذلك ، علينا أن نفكر في كيفية وصولنا إلى قاعدة البيانات.

بالمناسبة ، ما زلنا لا نملك قاعدة بيانات!

سنستخدم Entity Framework Core (سأسميها EF Core من أجل البساطة) كقاعدة بيانات ORM. يأتي هذا الإطار مع ASP.NET Core باعتباره ORM الافتراضي الخاص به ويكشف واجهة برمجة تطبيقات ودية تسمح لنا بتعيين فئات لتطبيقاتنا على جداول قاعدة البيانات.

يسمح لنا EF Core أيضًا بتصميم طلبنا أولاً ، ثم إنشاء قاعدة بيانات وفقًا لما حددناه في التعليمات البرمجية الخاصة بنا. هذه التقنية تسمى الكود أولاً. سنستخدم الطريقة الأولى للكود لإنشاء قاعدة بيانات (في هذا المثال ، في الواقع ، سأستخدم قاعدة بيانات في الذاكرة ، ولكن ستكون قادراً على تغييرها بسهولة إلى مثيل خادم SQL Server أو MySQL ، فمثلا).

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

داخل المجلد الجديد ، قم بإنشاء دليل جديد يسمى السياقات ، ثم قم بإضافة فئة جديدة تسمى AppDbContext. يجب أن يرث هذا الفصل DbContext ، حيث يستخدم فئة EF Core لتعيين نماذجك في جداول قاعدة البيانات. قم بتغيير الكود بالطريقة التالية:

المُنشئ الذي أضفناه إلى هذه الفئة مسؤول عن تمرير تكوين قاعدة البيانات إلى الفئة الأساسية من خلال حقن التبعية. سترى في لحظة كيف يعمل هذا.

الآن ، يتعين علينا إنشاء خاصيتين DbSet. هذه الخصائص عبارة عن مجموعات (مجموعات من الكائنات الفريدة) تقوم بتعيين النماذج لجداول قاعدة البيانات.

أيضًا ، يتعين علينا تعيين خصائص النماذج إلى أعمدة الجدول المعنية ، وتحديد الخصائص التي هي المفاتيح الأساسية ، والتي هي مفاتيح خارجية ، وأنواع الأعمدة ، وما إلى ذلك. يمكننا القيام بذلك بتجاوز الطريقة OnModelCreating ، باستخدام ميزة تسمى Fluent API to تحديد تعيين قاعدة البيانات. تغيير فئة AppDbContext كما يلي:

الكود بديهي.

نحدد الجداول التي يجب تعيين نماذجنا فيها. أيضًا ، نقوم بتعيين المفاتيح الأساسية ، باستخدام الأسلوب HasKey وأعمدة الجدول واستخدام طريقة الخاصية وبعض القيود مثل IsRequired و HasMaxLength و ValueGeneratedOnAdd ، وكل شيء مع تعبيرات lambda بطريقة "بطلاقة" (طرق التسلسل).

ألقِ نظرة على الكود التالي:

builder.Entity <الفئة> ()
       .HasMany (p => p.Products)
       .WithOne (p => p.Category)
       .HasForeignKey (p => p.CategoryId)؛

نحن هنا نحدد علاقة بين الجداول. نقول أن للفئة العديد من المنتجات ، وقمنا بتعيين الخصائص التي ستقوم بتعيين هذه العلاقة (المنتجات ، من الفئة ، والفئة ، من فئة المنتج). نحن أيضا تعيين المفتاح الخارجي (CategoryId).

ألق نظرة على هذا البرنامج التعليمي إذا كنت ترغب في معرفة كيفية تكوين العلاقات الشخصية بين شخص وآخر والعديد من الأطراف باستخدام EF Core ، وكذلك كيفية استخدامه ككل.

هناك أيضًا تكوين لبيانات البذر ، من خلال طريقة HasData:

builder.Entity <الفئة> (). HasData
(
  الفئة الجديدة {Id = 100 ، الاسم = "الفواكه والخضروات"} ،
  الفئة الجديدة {Id = 101 ، الاسم = "Dairy"}

نحن هنا ببساطة إضافة فئتين المثال افتراضيا. من الضروري اختبار نقطة نهاية واجهة برمجة التطبيقات بعد الانتهاء منها.

إشعار: نحن نقوم بتعيين خصائص المعرّف هنا يدويًا لأن الموفر في الذاكرة يتطلب تشغيله. أقوم بتعيين المعرفات على أعداد كبيرة لتجنب الاصطدام بين المعرفات التي تم إنشاؤها تلقائيًا وبيانات البذور.
لا يوجد هذا القيد في موفري قواعد البيانات العلائقية الحقيقية ، لذلك إذا كنت تريد استخدام قاعدة بيانات مثل SQL Server ، على سبيل المثال ، لا يتعين عليك تحديد هذه المعرفات. تحقق من مشكلة Github هذه إذا كنت تريد فهم هذا السلوك.

بعد تنفيذ فئة سياق قاعدة البيانات ، يمكننا تطبيق مستودع الفئات. إضافة مجلد جديد يسمى المستودعات داخل المجلد استمرار ، ثم قم بإضافة فئة جديدة تسمى BaseRepository.

هذه الفئة هي مجرد فئة تجريدية سوف ترثها جميع مستودعاتنا. الفصل التجريدي هو فصل ليس له مثيلات مباشرة. يجب عليك إنشاء فئات مباشرة لإنشاء المثيلات.

يستقبل BaseRepository مثيل AppDbContext الخاص بنا من خلال حقن التبعية ويكشف عن خاصية محمية (خاصية لا يمكن الوصول إليها إلا من خلال فئات الأطفال) تسمى _context ، والتي تتيح الوصول إلى جميع الطرق التي نحتاج إليها لمعالجة عمليات قاعدة البيانات.

إضافة فئة جديدة على نفس المجلد يسمى CategoryRepository. الآن سننفذ حقًا منطق المستودع:

مستودع يرث BaseRepository وينفذ ICategoryRepository.

لاحظ مدى بساطة تطبيق طريقة الإدراج. نستخدم قاعدة بيانات الفئات للوصول إلى جدول الفئات ، ثم ندعو إلى طريقة التمديد ToListAsync ، المسؤولة عن تحويل نتيجة استعلام إلى مجموعة من الفئات.

يقوم EF Core بترجمة استدعاء الأسلوب الخاص بنا إلى استعلام SQL ، الطريقة الأكثر فعالية قدر الإمكان. يتم تنفيذ الاستعلام فقط عند استدعاء طريقة من شأنها تحويل بياناتك إلى مجموعة ، أو عند استخدام طريقة لأخذ بيانات محددة.

لدينا الآن تنفيذ نظيف لوحدة التحكم في الفئات ، والخدمة والمستودع.

لقد فصلنا بين الاهتمامات وخلقنا فصولاً تفعل فقط ما يفترض أن تفعله.

الخطوة الأخيرة قبل اختبار التطبيق هي ربط واجهاتنا بالفئات المعنية باستخدام آلية حقن التبعية ASP.NET Core.

الخطوة 6 - تكوين حقن التبعية

لقد حان الوقت لكي تفهم أخيرًا كيف يعمل هذا المفهوم.

في المجلد الجذر للتطبيق ، افتح فئة بدء التشغيل. هذه الفئة مسؤولة عن تكوين جميع أنواع التكوينات عند بدء تشغيل التطبيق.

يتم استدعاء أساليب ConfigureServices و Configure في وقت التشغيل بواسطة خط أنابيب الإطار لتكوين كيفية عمل التطبيق والمكونات التي يجب استخدامه.

ألقِ نظرة على طريقة ConfigureServices. هنا لدينا سطر واحد فقط ، يقوم بتكوين التطبيق لاستخدام خط أنابيب MVC ، مما يعني في الأساس أن التطبيق سوف يتعامل مع الطلبات والاستجابات باستخدام فئات وحدة التحكم (هناك المزيد من الأشياء التي تحدث هنا وراء الكواليس ، ولكن هذا ما تحتاج إلى معرفته الى الان).

يمكننا استخدام طريقة ConfigureServices ، والوصول إلى معلمة الخدمات ، لتكوين روابط التبعية لدينا. قم بتنظيف رمز الفصل وإزالة جميع التعليقات وتغيير الرمز على النحو التالي:

انظر إلى هذا الكود:

services.AddDbContext  (خيارات => {
  options.UseInMemoryDatabase ( "سوبر ماركت-المعهد-في الذاكرة")؛
})؛

نحن هنا تكوين سياق قاعدة البيانات. نطلب من ASP.NET Core استخدام AppDbContext الخاص بنا مع تنفيذ قاعدة بيانات في الذاكرة ، والتي يتم تحديدها بواسطة السلسلة التي تم تمريرها كوسيطة لأسلوبنا. عادةً ما يتم استخدام الموفر في الذاكرة عند كتابة اختبارات التكامل ، لكنني أستخدمها هنا من أجل البساطة. بهذه الطريقة لا نحتاج إلى الاتصال بقاعدة بيانات حقيقية لاختبار التطبيق.

تكوين هذه الأسطر داخليًا يقوم بتكوين سياق قاعدة البيانات الخاصة بنا لحقن التبعية باستخدام عمر محدد.

يخبر العمر المحدد النطاق خط أنابيب ASP.NET Core أنه في كل مرة يحتاج فيها إلى حل فئة تتلقى مثيل AppDbContext كوسيطة مُنشئ ، يجب أن تستخدم نفس مثيل الفئة. إذا لم يكن هناك مثيل في الذاكرة ، فسيقوم خط الأنابيب بإنشاء مثيل جديد ، وإعادة استخدامه في جميع الفئات التي تحتاج إليها ، أثناء طلب معين. بهذه الطريقة ، لن تحتاج إلى إنشاء مثيل الفصل يدويًا عندما تحتاج إلى استخدامه.

هناك نطاقات أخرى مدى الحياة يمكنك التحقق من قراءة الوثائق الرسمية.

تمنحنا تقنية حقن التبعية العديد من المزايا ، مثل:

  • إعادة استخدام الكود ؛
  • إنتاجية أفضل ، لأنه عندما يتعين علينا تغيير التطبيق ، لا نحتاج إلى عناء لتغيير مئات الأماكن التي تستخدم فيها هذه الميزة ؛
  • يمكنك بسهولة اختبار التطبيق لأنه يمكننا عزل ما يتعين علينا اختباره باستخدام mocks (التنفيذ المزيف للفئات) حيث يتعين علينا اجتياز واجهات كوسيطات مُنشئ ؛
  • عندما يحتاج الفصل إلى تلقي مزيد من التبعيات من خلال مُنشئ ، لا يتعين عليك تغيير جميع الأماكن التي يتم فيها إنشاء المثيلات يدويًا (هذا رائع!).

بعد تكوين سياق قاعدة البيانات ، نربط أيضًا خدمتنا ومستودعنا بالفئات المعنية.

services.AddScoped  ()؛
services.AddScoped  ()؛

نحن هنا نستخدم أيضًا عمرًا محددًا لأن هذه الفئات يجب أن تستخدم فئة سياق قاعدة البيانات داخليًا. من المنطقي تحديد النطاق نفسه في هذه الحالة.

الآن بعد أن قمنا بتكوين روابط التبعية الخاصة بنا ، يتعين علينا إجراء تغيير بسيط في فئة البرنامج ، حتى تتمكن قاعدة البيانات من نشر بياناتنا الأولية بشكل صحيح. هذه الخطوة مطلوبة فقط عند استخدام موفر قاعدة البيانات في الذاكرة (راجع مشكلة Github هذه لفهم السبب).

كان من الضروري تغيير الطريقة الرئيسية لضمان أن قاعدة البيانات الخاصة بنا سوف يتم "إنشاؤها" عند بدء تشغيل التطبيق لأننا نستخدم موفر في الذاكرة. بدون هذا التغيير ، لن يتم إنشاء الفئات التي نريد نشرها.

مع تنفيذ جميع الميزات الأساسية ، فقد حان الوقت لاختبار نقطة نهاية واجهة برمجة التطبيقات.

الخطوة 7 - اختبار API الفئات

افتح المحطة الطرفية أو موجه الأوامر في المجلد الجذر API ، واكتب الأمر التالي:

تشغيل dotnet

الأمر أعلاه يبدأ التطبيق. ستقوم وحدة التحكم بعرض ناتج مشابه لهذا:

المعلومات: Microsoft.EntityFrameworkCore.Infrastructure [10403]
تهيئة Entity Framework Core 2.2.0-rtm-35687 "AppDbContext" باستخدام موفر "Microsoft.EntityFrameworkCore.InMemory" مع الخيارات: StoreName = supermarket-api-in-memory
المعلومات: Microsoft.EntityFrameworkCore.Update [30100]
تم حفظ كيانين في متجر في الذاكرة.
معلومات: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager [0]
الملف الشخصي للمستخدم هو متاح. استخدام "C: \ Users \ evgomes \ AppData \ Local \ ASP.NET \ DataProtection-Keys" كمستودع رئيسي و Windows DPAPI لتشفير المفاتيح أثناء الراحة.
بيئة الاستضافة: التنمية
مسار جذر المحتوى: C: \ Users \ evgomes \ Desktop \ Tutorials \ src \ Supermarket.API
استمع الآن إلى: https: // localhost: 5001
الآن الاستماع على: HTTP: // المضيف المحلي: 5000
بدأ التطبيق. اضغط على Ctrl + C للإغلاق.

يمكنك أن ترى أنه تم استدعاء EF Core لتهيئة قاعدة البيانات. تظهر الأسطر الأخيرة في أي المنافذ يعمل التطبيق.

افتح مستعرضًا وانتقل إلى http: // localhost: 5000 / api / Categories (أو إلى عنوان URL المعروض في إخراج وحدة التحكم). إذا رأيت خطأ أمان بسبب HTTPS ، فما عليك سوى إضافة استثناء للتطبيق.

سيقوم المستعرض بإظهار بيانات JSON التالية كإخراج:

[
  {
     "المعرف": 100 ،
     "الاسم": "الفواكه والخضروات" ،
     "منتجات": []
  }،
  {
     "المعرف": 101 ،
     "الاسم": "منتجات الألبان" ،
     "منتجات": []
  }
]

نرى هنا البيانات التي أضفناها إلى قاعدة البيانات عندما قمنا بتكوين سياق قاعدة البيانات. هذا الإخراج يؤكد أن كودنا يعمل.

لقد أنشأت نقطة نهاية GET API مع عدد قليل جدًا من أسطر التعليمات البرمجية ، ولديك بنية تعليمات برمجية يسهل تغييرها بالفعل بسبب بنية واجهة برمجة التطبيقات.

الآن ، حان الوقت لإظهار مدى سهولة تغيير هذا الرمز عندما يتعين عليك تعديله نظرًا لاحتياجات العمل.

الخطوة 8 - إنشاء مورد الفئة

إذا كنت تتذكر مواصفات نقطة نهاية واجهة برمجة التطبيقات ، فقد لاحظت أن استجابة JSON الفعلية لها خاصية إضافية واحدة: مجموعة من المنتجات. ألقِ نظرة على مثال الاستجابة المطلوبة:

{
  [
    {"id": 1 ، "name": "الفواكه والخضروات"} ،
    {"id": 2 ، "name": "Breads"} ،
    ... // فئات أخرى
  ]
}

مجموعة المنتجات موجودة في استجابة JSON الحالية نظرًا لأن طراز الفئة الخاص بنا يحتوي على خاصية منتجات ، والتي يحتاجها EF Core لتصحيح خريطة منتجات فئة معينة.

لا نريد رد هذه الخاصية ، لكن لا يمكننا تغيير فئة النموذج لاستبعاد هذه الخاصية. قد يتسبب ذلك في قيام EF Core بإلقاء الأخطاء عندما نحاول إدارة بيانات الفئات ، كما سيؤدي ذلك إلى كسر تصميم نموذج المجال الخاص بنا لأنه ليس من المنطقي أن يكون لديك فئة منتج ليس لديها منتجات.

لإرجاع بيانات JSON التي تحتوي فقط على معرفات وأسماء فئات السوبر ماركت ، يتعين علينا إنشاء فئة موارد.

فئة الموارد هي فئة تحتوي فقط على المعلومات الأساسية التي سيتم تبادلها بين تطبيقات العميل ونقاط النهاية لواجهة برمجة التطبيقات ، بشكل عام في شكل بيانات JSON ، لتمثيل بعض المعلومات المعينة.

يجب أن ترجع جميع الاستجابات من نقاط نهاية واجهة برمجة تطبيقات مورد.

من الممارسات السيئة إرجاع تمثيل النموذج الحقيقي باعتباره الرد لأنه يمكن أن يحتوي على معلومات لا يحتاجها تطبيق العميل أو أنه ليس لديه إذن بالحصول عليها (على سبيل المثال ، قد يعرض نموذج المستخدم معلومات كلمة مرور المستخدم ، والتي ستكون مشكلة أمنية كبيرة).

نحتاج إلى مورد لتمثيل فئاتنا فقط ، بدون المنتجات.

الآن بعد أن عرفت ما هو المورد ، فلننفذه. بادئ ذي بدء ، أوقف التطبيق قيد التشغيل بالضغط على Ctrl + C في سطر الأوامر. في المجلد الجذر للتطبيق ، قم بإنشاء مجلد جديد يسمى الموارد. هناك ، أضف فئة جديدة تسمى CategoryResource.

يتعين علينا تعيين مجموعة نماذج الفئات الخاصة بنا ، والتي يتم توفيرها بواسطة خدمة الفئات الخاصة بنا ، إلى مجموعة من موارد الفئات.

سنستخدم مكتبة تسمى AutoMapper لمعالجة التعيين بين الكائنات. AutoMapper هي مكتبة شائعة للغاية في العالم. NET ، ويستخدم في العديد من المشاريع التجارية مفتوحة المصدر.

اكتب الأسطر التالية في سطر الأوامر لإضافة AutoMapper إلى تطبيقنا:

إضافة dotnet حزمة AutoMapper
إضافة dotnet حزمة AutoMapper.Extensions.Microsoft.DependencyInjection

لاستخدام AutoMapper ، يتعين علينا القيام بأمرين:

  • تسجيله لحقن التبعية ؛
  • إنشاء فئة تخبر AutoMapper كيفية التعامل مع تعيين الفئات.

بادئ ذي بدء ، افتح فئة بدء التشغيل. في الأسلوب ConfigureServices ، بعد السطر الأخير ، أضف التعليمات البرمجية التالية:

services.AddAutoMapper ()؛

يعالج هذا الخط جميع التكوينات الضرورية لـ AutoMapper ، مثل تسجيله لحقن التبعية ومسح التطبيق أثناء بدء التشغيل لتكوين ملفات تخصيص التعيين.

الآن ، في الدليل الجذر ، أضف مجلدًا جديدًا يسمى Mapping ، ثم أضف فئة تسمى ModelToResourceProfile. قم بتغيير الكود بهذه الطريقة:

يرث الفصل ملف التعريف ، وهو نوع من الفصل يستخدمه AutoMapper للتحقق من كيفية عمل التعيينات لدينا. على المُنشئ ، نقوم بإنشاء خريطة بين فئة طراز الفئة وفئة تصنيف مصدر. نظرًا لأن خصائص الفئات لها نفس الأسماء والأنواع ، فلن يتعين علينا استخدام أي تكوين خاص لها.

تتمثل الخطوة الأخيرة في تغيير وحدة تحكم الفئات لاستخدام أداة AutoMapper لمعالجة تعيين الكائنات الخاصة بنا.

لقد غيرت المنشئ لتلقي مثيل تطبيق IMapper. يمكنك استخدام أساليب الواجهة هذه لاستخدام أساليب تعيين AutoMapper.

لقد غيرت أيضًا طريقة GetAllAsync لتعيين تعداد الفئات الخاص بنا إلى تعداد للموارد باستخدام طريقة Map. تتلقى هذه الطريقة مثيلًا للفئة أو المجموعة التي نريد تعيينها ، ومن خلال تعريفات النوع العام ، تحدد نوع الفصل أو المجموعة الذي يجب تعيينه.

لاحظ أننا غيرنا التنفيذ بسهولة دون الحاجة إلى تكييف فئة الخدمة أو المستودع ، وذلك ببساطة عن طريق ضخ تبعية جديدة (IMapper) إلى المُنشئ.

يعمل حقن التبعية على جعل تطبيقك قابلاً للصيانة وسهل التغيير نظرًا لأنك لست مضطرًا إلى كسر كل تطبيق التعليمات البرمجية لإضافة ميزات أو إزالتها.

ربما أدركت أنه ليس فقط فئة وحدة التحكم ولكن جميع الفئات التي تتلقى تبعيات (بما في ذلك التبعيات نفسها) تم حلها تلقائيًا لتلقي الفئات الصحيحة وفقًا لتكوينات الربط.

حقن التبعية مذهل ، أليس كذلك؟

الآن ، ابدأ واجهة برمجة التطبيقات مرة أخرى باستخدام الأمر dotnet run وتوجه إلى http: // localhost: 5000 / api / classes لرؤية استجابة JSON الجديدة.

هذه هي بيانات الاستجابة التي يجب أن تراها

لدينا بالفعل لدينا نقطة النهاية GET. الآن ، لنقم بإنشاء نقطة نهاية جديدة لفئات POST (إنشاء).

الخطوة 9 - إنشاء فئات جديدة

عند التعامل مع إنشاء الموارد ، يجب أن نهتم بأشياء كثيرة ، مثل:

  • التحقق من صحة البيانات وسلامة البيانات ؛
  • إذن لخلق الموارد ؛
  • معالجة الأخطاء؛
  • تسجيل.

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

أيضًا ، هناك إطار شائع جدًا يسمى ASP.NET Identity يوفر حلولًا مضمنة فيما يتعلق بالأمان وتسجيل المستخدمين والتي يمكنك استخدامها في تطبيقاتك. يتضمن موفرين للعمل مع EF Core ، مثل IdentityDbContext مضمن يمكنك استخدامه. يمكنك معرفة المزيد عن ذلك هنا.

دعنا نكتب نقطة نهاية HTTP POST تغطي السيناريوهات الأخرى (باستثناء التسجيل ، والتي يمكن أن تتغير وفقًا لنطاقات وأدوات مختلفة).

قبل إنشاء نقطة النهاية الجديدة ، نحتاج إلى مورد جديد. سيحدد هذا المورد البيانات التي ترسلها تطبيقات العميل إلى نقطة النهاية (في هذه الحالة ، اسم الفئة) إلى فئة من تطبيقنا.

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

في مجلد "الموارد" ، أضف فئة جديدة تسمى SaveCategoryResource:

لاحظ السمات المطلوبة و MaxLength المطبقة على خاصية الاسم. تسمى هذه السمات تعليقات توضيحية للبيانات. يستخدم خط أنابيب ASP.NET Core بيانات التعريف هذه للتحقق من صحة الطلبات والردود. كما تشير الأسماء ، اسم الفئة مطلوب ويبلغ طوله الأقصى 30 حرفًا.

الآن دعونا نحدد شكل نقطة نهاية واجهة برمجة التطبيقات الجديدة. أضف التعليمات البرمجية التالية إلى وحدة تحكم الفئات:

نقول للإطار أن هذه نقطة نهاية HTTP POST باستخدام سمة HttpPost.

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

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

هناك العديد من أنواع أنواع الإجراءات التي يمكنك استخدامها كاستجابة ، ولكن عمومًا ، يمكننا استخدام هذه الواجهة ، وسيستخدم ASP.NET Core فئة افتراضية لذلك.

تخبر السمة FromBody ASP.NET Core بتحليل بيانات نص الطلب في فئة الموارد الجديدة الخاصة بنا. يعني ذلك أنه عندما يتم إرسال JSON يحتوي على اسم الفئة إلى طلبنا ، فسيقوم الإطار تلقائيًا بتحليله إلى صفنا الجديد.

الآن ، دعونا ننفذ منطق الطريق. يجب أن نتبع بعض الخطوات لإنشاء فئة جديدة بنجاح:

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

يبدو الأمر معقدًا ، لكن من السهل تطبيق هذا المنطق باستخدام بنية الخدمة التي صممناها لواجهة برمجة التطبيقات.

لنبدأ من خلال التحقق من صحة الطلب الوارد.

الخطوة 10 - التحقق من صحة نص الطلب باستخدام حالة النموذج

تحتوي وحدات تحكم ASP.NET Core على خاصية تسمى ModelState. يتم ملء هذه الخاصية أثناء تنفيذ الطلب قبل الوصول إلى تنفيذ الإجراء الخاص بنا. إنه مثيل لـ ModelStateDictionary ، فئة تحتوي على معلومات مثل ما إذا كان الطلب صالحًا ورسائل خطأ محتملة في التحقق من الصحة.

قم بتغيير رمز نقطة النهاية كما يلي:

يتحقق الكود من حالة النموذج (في هذه الحالة ، البيانات المرسلة في نص الطلب) غير صالحة ، والتحقق من التعليقات التوضيحية للبيانات الخاصة بنا. إذا لم يكن الأمر كذلك ، فسوف تُرجع واجهة برمجة التطبيقات طلبًا سيئًا (مع رمز الحالة 400) ورسائل الخطأ الافتراضية التي قدمت بيانات تعريف التعليقات التوضيحية الخاصة بنا.

لم يتم تطبيق طريقة ModelState.GetErrorMessages () حتى الآن. إنها طريقة امتداد (طريقة تعمل على توسيع وظائف فئة أو واجهة موجودة بالفعل) وسأقوم بتنفيذها لتحويل أخطاء التحقق من الصحة إلى سلاسل بسيطة للعودة إلى العميل.

إضافة مجلد جديد ملحقات في جذر API لدينا ثم قم بإضافة فئة جديدة ModelStateExtensions.

يجب أن تكون جميع طرق الامتداد ثابتة ، وكذلك الفئات التي يتم الإعلان عنها فيها. يعني ذلك أنهم لا يتعاملون مع بيانات مثيل محددة وأنه يتم تحميلها مرة واحدة فقط عند بدء تشغيل التطبيق.

تخبر هذه الكلمة الأساسية أمام إعلان المعلمة المحول البرمجي C # بمعاملتها كطريقة ملحق. والنتيجة هي أننا يمكن أن نسميها كطريقة عادية لهذه الفئة لأننا نقوم بتضمين الأمر باستخدام التوجيه حيث نريد استخدام الامتداد.

يستخدم الملحق استعلامات LINQ ، وهي ميزة مفيدة للغاية في .NET تتيح لنا الاستعلام عن البيانات وتحويلها باستخدام تعبيرات قابلة للتسلسل. تقوم التعبيرات هنا بتحويل أساليب خطأ التحقق من الصحة إلى قائمة من السلاسل التي تحتوي على رسائل الخطأ.

استيراد مساحة الاسم Supermarket.API.Extensions إلى وحدة تحكم الفئات قبل الانتقال إلى الخطوة التالية.

باستخدام Supermarket.API.Extensions ؛

دعنا نواصل تنفيذ منطق نقطة النهاية لدينا عن طريق تعيين موردنا الجديد إلى فئة نموذج فئة.

الخطوة 11 - تعيين المورد الجديد

لقد حددنا بالفعل ملف تعريف التعيين لتحويل النماذج إلى موارد. نحتاج الآن إلى ملف تعريف جديد يعمل معكوس.

إضافة فئة جديدة ResourceToModelProfile في مجلد التعيين:

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

الآن يمكننا تعيين موردنا الجديد إلى الفئة النموذجية المعنية:

الخطوة 12 - تطبيق نموذج طلب - استجابة للتعامل مع منطق الحفظ

الآن علينا تنفيذ المنطق الأكثر إثارة للاهتمام: لحفظ فئة جديدة. نتوقع خدمتنا للقيام بذلك.

قد يفشل منطق الحفظ بسبب مشاكل عند الاتصال بقاعدة البيانات ، أو ربما لأن أي قاعدة عمل داخلية تبطل بياناتنا.

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

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

يمكننا تطبيق هذه الميزة من خلال تطبيق نمط الاستجابة للطلب. يقوم نمط تصميم المؤسسة هذا بتغليف معلمات الطلب والاستجابة الخاصة بنا في الفصول كوسيلة لتغليف المعلومات التي ستستخدمها خدماتنا لمعالجة بعض المهام وإرجاع المعلومات إلى الفصل الذي يستخدم الخدمة.

يعطينا هذا النمط بعض المزايا ، مثل:

  • إذا كنا بحاجة إلى تغيير خدمتنا لتلقي المزيد من المعلمات ، فلن نضطر إلى كسر توقيعها ؛
  • يمكننا تحديد عقد قياسي لطلبنا و / أو الردود ؛
  • يمكننا التعامل مع منطق الأعمال والإخفاقات المحتملة دون إيقاف عملية التطبيق ، ولن نحتاج إلى استخدام الكثير من كتل تجربة المحاولة.

لنقم بإنشاء نوع استجابة قياسي لأساليب خدماتنا التي تتعامل مع تغييرات البيانات. لكل طلب من هذا النوع ، نريد أن نعرف إذا تم تنفيذ الطلب دون أي مشاكل. إذا فشلت ، فنحن نريد إرجاع رسالة خطأ إلى العميل.

في مجلد المجال ، داخل الخدمات ، أضف دليلًا جديدًا يسمى الاتصالات. أضف فئة جديدة تسمى BaseResponse.

إنها فئة تجريدية سترثها أنواع ردودنا.

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

لاحظ أن هذه الخصائص مطلوبة وأن الفئات الموروثة فقط هي التي يمكنها ضبط هذه البيانات لأن الفئات الفرعية يجب أن تمر هذه المعلومات من خلال وظيفة المنشئ.

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

الآن ، في نفس المجلد ، أضف فئة جديدة تسمى SaveCategoryResponse.

يقوم نوع الاستجابة أيضًا بتعيين خاصية الفئة ، والتي ستحتوي على بيانات الفئة الخاصة بنا في حالة انتهاء الطلب بنجاح.

لاحظ أنني قمت بتعريف ثلاثة مُنشئات مختلفة لهذه الفئة:

  • خاص ، والذي سيتم تمرير معلمات النجاح والرسالة إلى الفئة الأساسية ، وكذلك تعيين خاصية الفئة ؛
  • مُنشئ يستقبل فقط الفئة كمعلمة. هذا واحد سوف يخلق استجابة ناجحة ، استدعاء المنشئ الخاص لتعيين الخصائص المعنية ؛
  • مُنشئ ثالث يحدد الرسالة فقط. سيتم استخدام هذا لإنشاء استجابة فشل.

نظرًا لأن C # يدعم العديد من المُنشئات ، فقد قمنا بتبسيط عملية إنشاء الاستجابة دون تحديد طريقة مختلفة للتعامل مع ذلك ، فقط عن طريق استخدام مُنشئين مختلفين.

يمكننا الآن تغيير واجهة خدمتنا لإضافة عقد طريقة الحفظ الجديد.

قم بتغيير واجهة ICategoryService كما يلي:

سنقوم ببساطة بتمرير فئة إلى هذه الطريقة ، وسوف تتعامل مع كل المنطق اللازم لحفظ بيانات النموذج ، وتنسيق مستودعات وغيرها من الخدمات الضرورية للقيام بذلك.

لاحظ أنني لا أقوم بإنشاء فصل طلب معين هنا لأننا لسنا بحاجة إلى أي معلمات أخرى لأداء هذه المهمة. هناك مفهوم في برمجة الكمبيوتر يسمى KISS - اختصار لـ Keep it Simple، Stupid. في الأساس ، تقول أنه يجب أن تبقي طلبك بسيطًا قدر الإمكان.

تذكر ذلك عند تصميم التطبيقات الخاصة بك: قم فقط بتطبيق ما تحتاجه لحل مشكلة ما. لا تبالغ في تطبيقك.

الآن يمكننا الانتهاء من منطق نقطة النهاية لدينا:

بعد التحقق من صحة بيانات الطلب وتعيين المورد لنموذجنا ، نقوم بتمريرها إلى خدمتنا لاستمرار البيانات.

إذا فشل شيء ما ، ترجع واجهة برمجة التطبيقات طلبًا غير صحيح إذا لم يكن الأمر كذلك ، تقوم واجهة برمجة التطبيقات (API) بتعيين الفئة الجديدة (بما في ذلك الآن البيانات مثل المعرف الجديد) إلى CategoryResource الذي تم إنشاؤه مسبقًا وإرسالها إلى العميل.

الآن لننفذ المنطق الحقيقي للخدمة.

الخطوة 13 - منطق قاعدة البيانات ووحدة نمط العمل

نظرًا لأننا سنستمر في البيانات في قاعدة البيانات ، نحتاج إلى طريقة جديدة في مستودعنا.

أضف طريقة AddAsync جديدة إلى واجهة ICategoryRepository:

الآن ، دعونا ننفذ هذه الطريقة في فصل المستودع الحقيقي الخاص بنا:

نحن هنا ببساطة نضيف فئة جديدة إلى مجموعتنا.

عندما نضيف فئة إلى DBSet <> ، يبدأ EF Core في تتبع جميع التغييرات التي تحدث لنموذجنا ويستخدم هذه البيانات في الحالة الحالية لإنشاء استعلامات من شأنها إدراج أو تحديث أو حذف النماذج.

يضيف التطبيق الحالي ببساطة النموذج إلى مجموعتنا ، لكن بياناتنا لا تزال غير محفوظة.

هناك طريقة تسمى SaveChanges موجودة في فئة السياق التي يجب أن ندعوها لتنفيذ الاستعلامات بالفعل في قاعدة البيانات. لم أسميها هنا لأن المستودع يجب ألا يستمر في البيانات ، إنه مجرد مجموعة من الكائنات في الذاكرة.

هذا الموضوع مثير للجدل للغاية حتى بين مطوري .NET ذوي الخبرة ، ولكن اسمحوا لي أن أشرح لك لماذا لا يجب استدعاء SaveChanges في فئات المستودعات.

يمكننا أن نفكر في مستودع من الناحية النظرية مثل أي مجموعة أخرى موجودة في .NET Framework. عند التعامل مع مجموعة في .NET (والعديد من لغات البرمجة الأخرى ، مثل Javascript و Java) ، يمكنك عمومًا:

  • أضف عناصر جديدة إليها (مثل عند دفع البيانات إلى القوائم والمصفوفات والقواميس) ؛
  • البحث عن أو تصفية العناصر ؛
  • إزالة عنصر من المجموعة ؛
  • استبدال عنصر معين ، أو تحديثه.

فكر في قائمة من العالم الحقيقي. تخيل أنك تكتب قائمة تسوق لشراء الأشياء من السوبر ماركت (يا لها من مصادفة ، لا؟).

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

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

إذا كنت ترغب في "حفظ" قوائم الفواكه (في هذه الحالة ، لشراء جميع الفواكه) ، فأنت تدفعها ويقوم السوبر ماركت بمعالجة بيانات الأسهم للتحقق مما إذا كان يتعين عليهم شراء المزيد من الفواكه من مزود أم لا.

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

هناك مشكلة أخرى عند حفظ البيانات مباشرة في مستودع: لا يمكنك استخدام المعاملات.

تخيل أن تطبيقنا لديه آلية تسجيل تخزن بعض اسم المستخدم والإجراء الذي يتم تنفيذه في كل مرة يتم فيها إجراء تغيير على بيانات واجهة برمجة التطبيقات.

الآن تخيل أنه ، لسبب ما ، لديك مكالمة إلى خدمة تقوم بتحديث اسم المستخدم (ليس سيناريو شائعًا ، ولكن دعونا ننظر فيه).

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

تخيل الآن أننا قمنا بتطبيق طريقة التحديث للمستخدمين وسجلات في مستودعات مختلفة ، وكلاهما استدعاء SaveChanges. ماذا يحدث إذا فشلت إحدى هذه الطرق في منتصف عملية التحديث؟ سينتهي بك الأمر إلى عدم تناسق البيانات.

يجب أن نحفظ تغييراتنا في قاعدة البيانات فقط بعد انتهاء كل شيء. للقيام بذلك ، يتعين علينا استخدام معاملة ، والتي هي في الأساس ميزة تنفذها معظم قواعد البيانات لحفظ البيانات فقط بعد انتهاء عملية معقدة.

"- حسنًا ، إذا لم نتمكن من حفظ الأشياء هنا ، فأين يجب أن نفعل ذلك؟"

نمط شائع للتعامل مع هذه المشكلة هو وحدة نمط العمل. يتكون هذا النمط من فئة تتلقى مثيل AppDbContext الخاص بنا كتبعية وتعرض طرقًا لبدء المعاملات أو إكمالها أو إجهاضها.

سنستخدم تطبيقًا بسيطًا لوحدة العمل لمعالجة مشكلتنا هنا.

أضف واجهة جديدة داخل مجلد المستودعات من طبقة المجال تسمى IUnitOfWork:

كما ترون ، فإنه يكشف فقط الطريقة التي ستكمل عمليات إدارة البيانات بشكل غير متزامن.

دعنا نضيف التنفيذ الحقيقي الآن.

أضف فئة جديدة تسمى UnitOfWork في مجلد RepositoriesRepositories الخاص بطبقة المثابرة:

هذا تطبيق بسيط ونظيف سيوفر فقط جميع التغييرات في قاعدة البيانات بعد الانتهاء من تعديلها باستخدام مستودعاتك.

إذا بحثت عن تطبيقات نمط وحدة العمل ، فستجد تطبيقات أكثر تعقيدًا تنفذ عمليات الاستعادة.

نظرًا لأن EF Core يطبق بالفعل نمط المخزون ووحدة العمل وراء الكواليس ، فلا داعي لأن نهتم بأسلوب الاستعادة.

" - ماذا؟ إذن لماذا يتعين علينا إنشاء كل هذه الواجهات والفئات؟ "

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

تخيل أنك ستقرر في المستقبل تغيير إطار عمل ORM إلى إطار آخر ، مثل Dapper ، على سبيل المثال ، أو إذا كان عليك تنفيذ استعلامات SQL بسيطة بسبب الأداء. إذا قمت بربط منطق استعلاماتك بخدماتك ، فسيكون من الصعب تغيير المنطق ، لأنه سيتعين عليك القيام بذلك في العديد من الفصول.

باستخدام نمط مستودع التخزين ، يمكنك ببساطة تنفيذ فئة مستودع تخزين جديدة وربطها باستخدام حقن التبعية.

لذلك ، إذا كنت تستخدم EF Core مباشرةً في خدماتك وكان عليك تغيير شيء ما ، فهذا ما ستحصل عليه:

كما قلت ، تنفذ EF Core وحدة العمل وأنماط مستودع خلف الكواليس. يمكننا اعتبار خصائص DbSet <> الخاصة بنا مستودعات. أيضا ، SaveChanges تستمر فقط البيانات في حالة النجاح لجميع عمليات قاعدة البيانات.

الآن بعد أن تعرف ما هي وحدة العمل وسبب استخدامها مع المستودعات ، فلننفّذ منطق الخدمة الحقيقية.

بفضل البنية المنفصلة الخاصة بنا ، يمكننا ببساطة تمرير مثيل من UnitOfWork كاعتماد على هذه الفئة.

منطق عملنا بسيط للغاية.

أولاً ، نحاول إضافة الفئة الجديدة إلى قاعدة البيانات ثم محاولة API حفظها ، مع لف كل شيء داخل كتلة try-catch.

إذا فشل شيء ما ، فإن API تستدعي بعض خدمات التسجيل الخيالية وإرجاع استجابة تشير إلى الفشل.

إذا انتهت العملية دون أي مشاكل ، فسيرجع التطبيق استجابة ناجحة ، وإرسال بيانات الفئة الخاصة بنا. بسيط ، أليس كذلك؟

نصيحة: في تطبيقات العالم الواقعي ، يجب ألا تقوم بلف كل شيء داخل كتلة تجريبية عامة ، ولكن بدلاً من ذلك يجب عليك معالجة جميع الأخطاء المحتملة بشكل منفصل.
ببساطة إضافة كتلة try-catch لن تغطي معظم السيناريوهات الفاشلة المحتملة. تأكد من تصحيح تطبيق معالجة الأخطاء.

الخطوة الأخيرة قبل اختبار واجهة برمجة التطبيقات لدينا هي ربط وحدة واجهة العمل بفصلها.

أضف هذا السطر الجديد إلى طريقة ConfigureServices لفئة بدء التشغيل:

services.AddScoped  ()؛

الآن دعونا نختبرها!

الخطوة 14 - اختبار POST Endpoint لدينا باستخدام ساعي البريد

بدء تطبيقنا مرة أخرى باستخدام تشغيل dotnet.

لا يمكننا استخدام المتصفح لاختبار نقطة نهاية POST. دعونا نستخدم Postman لاختبار نقاط النهاية لدينا. إنها أداة مفيدة جدًا لاختبار واجهات برمجة التطبيقات (RESTful).

افتح ساعي البريد وأغلق رسائل التقديم. سترى شاشة مثل هذه:

شاشة تظهر خيارات لاختبار نقاط النهاية

تغيير GET المحدد بشكل افتراضي في مربع التحديد إلى POST.

اكتب عنوان API في حقل إدخال عنوان URL للطلب.

يتعين علينا تقديم بيانات نص الطلب لإرسالها إلى API الخاصة بنا. انقر فوق عنصر قائمة النص الأساسي ، ثم قم بتغيير الخيار المعروض أدناه إلى خام.

ساعي البريد سوف تظهر خيار النص في اليمين. قم بتغييره إلى JSON (application / json) والصق بيانات JSON التالية أدناه:

{
  "اسم": ""
}
شاشة فقط قبل إرسال الطلب

كما ترى ، سنرسل سلسلة اسم فارغة إلى نقطة النهاية الجديدة.

انقر فوق الزر إرسال. ستتلقى مخرجات مثل هذا:

كما ترى ، يعمل منطق التحقق من الصحة الخاص بنا!

هل تتذكر منطق التحقق الذي أنشأناه لنقطة النهاية؟ هذا الإخراج هو دليل على أنه يعمل!

لاحظ أيضًا رمز الحالة 400 المعروض على اليمين. تضيف نتيجة BadRequest رمز الحالة هذا تلقائيًا إلى الاستجابة.

الآن ، دعونا نغير بيانات JSON إلى واحدة صالحة لرؤية الاستجابة الجديدة:

أخيرًا ، النتيجة التي توقعناها

إنشاء API بشكل صحيح موردنا الجديد.

حتى الآن ، يمكن أن API لدينا قائمة وإنشاء فئات. لقد تعلمت الكثير من الأشياء حول لغة C # وإطار ASP.NET Core وكذلك أساليب التصميم الشائعة لبناء واجهات برمجة التطبيقات الخاصة بك.

دعنا نواصل API الفئات لدينا خلق نقطة النهاية لتحديث الفئات.

من الآن فصاعدًا ، بما أنني أوضحت لك معظم المفاهيم ، سأسرع في شرحها وأركز على مواضيع جديدة حتى لا تضيع وقتك. لنذهب!

الخطوة 15 - تحديث الفئات

لتحديث الفئات ، نحتاج إلى نقطة نهاية HTTP PUT.

إن المنطق الذي يجب أن نضعه في الكود مشابه جدًا لمنهج POST:

  • أولاً ، يتعين علينا التحقق من صحة الطلب الوارد باستخدام ModelState ؛
  • إذا كان الطلب صالحًا ، يجب على API تعيين المورد الوارد إلى فئة طراز باستخدام AutoMapper ؛
  • بعد ذلك ، نحتاج إلى الاتصال بخدمتنا ، لإخبارنا بتحديث الفئة ، وتوفير معرف الفئة المعني والبيانات المحدثة ؛
  • إذا لم تكن هناك فئة ذات المعرف المحدد في قاعدة البيانات ، فسنعيد طلبًا سيئًا. يمكننا استخدام نتيجة NotFound بدلاً من ذلك ، لكن لا يهم هذا النطاق حقًا ، حيث نوفر رسالة خطأ إلى تطبيقات العميل ؛
  • إذا تم تنفيذ منطق الحفظ بشكل صحيح ، يجب أن تُرجع الخدمة استجابة تحتوي على بيانات الفئة المحدّثة. إذا لم يكن الأمر كذلك ، فيجب أن يقدم لنا إشارة إلى فشل العملية ورسالة توضح السبب ؛
  • أخيرًا ، إذا حدث خطأ ، فسوف تُرجع واجهة برمجة التطبيقات طلبًا سيئًا. إذا لم يكن كذلك ، فإنه يعيّن طراز الفئة المحدّث إلى مورد فئة وإرجاع استجابة نجاح إلى تطبيق العميل.

دعنا نضيف طريقة PutAsync الجديدة إلى فئة التحكم:

إذا قارنته بمنطق POST ، ستلاحظ وجود اختلاف واحد فقط هنا: تحدد السمة HttPut معلمة يجب أن يتلقاها المسار المحدد.

سنتصل بنقطة النهاية هذه لتحديد معرف الفئة باعتباره جزء URL الأخير ، مثل / api / Categories / 1. تحليل خط أنابيب ASP.NET Core هذه القطعة إلى المعلمة التي تحمل الاسم نفسه.

الآن يتعين علينا تحديد توقيع أسلوب UpdateAsync في واجهة ICategoryService:

الآن دعنا ننتقل إلى المنطق الحقيقي.

الخطوة 16 - تحديث المنطق

لتحديث فئتنا ، أولاً ، نحتاج إلى إرجاع البيانات الحالية من قاعدة البيانات ، إذا كانت موجودة. نحتاج أيضًا إلى تحديثه في DBSet <>.

دعنا نضيف عقدين من الطرق الجديدة إلى واجهة ICategoryService لدينا:

لقد حددنا طريقة FindByIdAsync ، والتي ستقوم بإرجاع فئة بشكل غير متزامن من قاعدة البيانات وطريقة التحديث. انتبه إلى أن طريقة التحديث ليست غير متزامنة لأن واجهة برمجة تطبيقات EF Core لا تتطلب طريقة غير متزامنة لتحديث النماذج.

الآن ، دعونا ننفذ المنطق الحقيقي في فئة السجل المادي:

أخيرًا يمكننا تشفير منطق الخدمة:

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

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

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

قم بتشغيل التطبيق مرة أخرى ، وباستخدام Postman ، أضف فئة جديدة إلى قاعدة البيانات:

إضافة فئة جديدة لتحديثها في وقت لاحق

امتلاك معرف صالح في يديك ، قم بتغيير خيار POST إلى PUT في مربع التحديد وأضف قيمة المعرف في نهاية عنوان URL. تغيير خاصية الاسم إلى اسم مختلف وإرسال الطلب للتحقق من النتيجة:

تم تحديث بيانات الفئة بنجاح

يمكنك إرسال طلب GET إلى نقطة نهاية واجهة برمجة التطبيقات (API) لضمان تحرير اسم الفئة بشكل صحيح:

هذه نتيجة طلب GET الآن

آخر عملية يتعين علينا تنفيذها للفئات هي استبعاد الفئات. دعونا نفعل ذلك بإنشاء نقطة نهاية حذف HTTP.

الخطوة 17 - حذف الفئات

من السهل حقًا تنفيذ منطق حذف الفئات لأن معظم الطرق التي نحتاجها قد تم إنشاؤها مسبقًا.

هذه هي الخطوات اللازمة لطريقنا للعمل:

  • يحتاج API إلى الاتصال بخدمتنا ، لإخباره بحذف فئتنا ، وتوفير الرقم التعريفي الخاص به ؛
  • في حالة عدم وجود فئة ذات المعرف المحدد في قاعدة البيانات ، يجب أن تُرجع الخدمة رسالة تشير إليها ؛
  • إذا تم تنفيذ منطق الحذف دون أي مشاكل ، يجب على الخدمة إرجاع استجابة تحتوي على بيانات الفئة المحذوفة. إذا لم يكن الأمر كذلك ، فيجب أن يقدم لنا إشارة إلى فشل العملية ورسالة خطأ محتملة ؛
  • أخيرًا ، إذا حدث خطأ ، فسوف تُرجع واجهة برمجة التطبيقات طلبًا سيئًا. إذا لم يكن الأمر كذلك ، تقوم واجهة برمجة التطبيقات (API) بتعيين الفئة المحدّثة إلى مورد وإرجاع استجابة نجاح إلى العميل.

لنبدأ بإضافة منطق نقطة النهاية الجديد:

تحدد السمة HttpDelete أيضًا قالب معرف.

قبل إضافة توقيع DeleteAsync إلى واجهة خدمة ICategoryService الخاصة بنا ، نحتاج إلى إجراء إعادة بيع صغيرة.

يجب أن تُرجع طريقة الخدمة الجديدة استجابة تحتوي على بيانات الفئة ، بنفس الطريقة التي اتبعناها لطريقتي PostAsync و UpdateAsync. يمكننا إعادة استخدام SaveCategoryResponse لهذا الغرض ، لكننا لا نحفظ البيانات في هذه الحالة.

لتجنب إنشاء فئة جديدة بنفس الشكل لتقديم هذا المطلب ، يمكننا ببساطة إعادة تسمية SaveCategoryResponse إلى CategoryResponse.

إذا كنت تستخدم Visual Studio Code ، فيمكنك فتح فئة SaveCategoryResponse ، ووضع مؤشر الماوس فوق اسم الفصل واستخدام الخيار Change All Occurrences لإعادة تسمية الفئة:

طريقة سهلة لتغيير الاسم في جميع الملفات

تأكد من إعادة تسمية اسم الملف أيضًا.

دعنا نضيف توقيع أسلوب DeleteAsync إلى واجهة ICategoryService:

قبل تنفيذ منطق الحذف ، نحتاج إلى طريقة جديدة في مستودعنا.

أضف توقيع الأسلوب Remove إلى واجهة ICategoryRepository:

void Remove (فئة الفئة) ؛

والآن قم بإضافة التطبيق الحقيقي على فئة المستودع:

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

أخيرًا ، دعنا ننفذ المنطق على فئة خدمة الفئة:

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

"- مهلا ، ولكن ماذا عن منتجات كل فئة؟ ألا تحتاج إلى إنشاء مستودع وحذف المنتجات أولاً ، لتجنب الأخطاء؟ "

الجواب هو لا. بفضل آلية التتبع EF Core ، عندما نقوم بتحميل نموذج من قاعدة البيانات ، يعرف الإطار العلاقات التي يمتلكها النموذج. إذا قمنا بحذفها ، فإن EF Core تعلم أنه يجب عليها حذف جميع الطرز ذات الصلة أولاً ، بشكل متكرر.

يمكننا تعطيل هذه الميزة عند تعيين فئاتنا إلى جداول قاعدة البيانات ، ولكنها خارج نطاق هذا البرنامج التعليمي. ألقِ نظرة هنا إذا كنت تريد التعرف على هذه الميزة.

حان الوقت لاختبار نقطة النهاية الجديدة الخاصة بنا. قم بتشغيل التطبيق مرة أخرى وإرسال طلب DELETE باستخدام ساعي البريد كما يلي:

كما ترى ، حذف API الفئة الحالية دون أي مشاكل

يمكننا التحقق من أن API الخاصة بنا تعمل بشكل صحيح عن طريق إرسال طلب GET:

الآن نتلقى فئة واحدة فقط نتيجة لذلك

لقد انتهينا من فئات API. حان الآن وقت الانتقال إلى واجهة برمجة تطبيقات المنتجات.

الخطوة 18 - واجهة برمجة تطبيقات المنتجات

لقد تعلمت حتى الآن كيفية تنفيذ جميع أفعال HTTP الأساسية للتعامل مع عمليات CRUD باستخدام ASP.NET Core. دعنا ننتقل إلى المستوى التالي لتطبيق API منتجاتنا.

لن أفصل جميع أفعال HTTP مرة أخرى لأنه سيكون شاملاً. بالنسبة للجزء الأخير من هذا البرنامج التعليمي ، سأغطي فقط طلب GET ، لتوضيح كيفية تضمين الكيانات ذات الصلة عند الاستعلام عن البيانات من قاعدة البيانات وكيفية استخدام سمات الوصف التي حددناها لقيم تعداد EUnitOfMeasurement.

إضافة وحدة تحكم جديدة في المجلد Controllers يسمى ProductsController.

قبل ترميز أي شيء هنا ، يتعين علينا إنشاء مورد المنتج.

اسمح لي بتحديث ذاكرتك مع عرض كيف سيبدو موردنا:

{
 [
  {
   "معرف": 1 ،
   "الاسم": "السكر" ،
   "كميةحزمة": 1 ،
   "unitOfMeasurement": "KG"
   "الفئة": {
   "معرف": 3 ،
   "الاسم": "السكر"
   }
  }،
  … // منتجات اخرى
 ]
}

نريد مجموعة JSON تحتوي على جميع المنتجات من قاعدة البيانات.

تختلف بيانات JSON عن طراز المنتج عن طريق شيئين:

  • يتم عرض وحدة القياس بطريقة أقصر ، مع إظهار اختصارها فقط ؛
  • نقوم بإخراج بيانات الفئة دون تضمين خاصية CategoryId.

لتمثيل وحدة القياس ، يمكننا استخدام خاصية سلسلة بسيطة بدلاً من نوع التعداد (بالمناسبة ، ليس لدينا نوع تعداد افتراضي لبيانات JSON ، لذلك يتعين علينا تحويله إلى نوع مختلف).

الآن وبعد أن أصبحنا الآن كيفية تشكيل المورد الجديد ، فلننشئه. إضافة فئة جديدة ProductResource إلى مجلد الموارد:

الآن يتعين علينا تكوين التعيين بين فئة النموذج وفئة الموارد الجديدة لدينا.

سيكون تكوين التعيين مماثلًا للتكوينات المستخدمة في التعيينات الأخرى ، ولكن يتعين علينا هنا معالجة تحول تعداد EUnitOfMeasurement إلى سلسلة.

هل تتذكر سمة StringValue المطبقة على أنواع التعداد؟ الآن سأوضح لك كيفية استخراج هذه المعلومات باستخدام ميزة قوية لإطار عمل .NET: واجهة برمجة تطبيقات Reflection.

واجهة برمجة تطبيقات Reflection هي مجموعة قوية من الموارد التي تتيح لنا استخراج البيانات الوصفية ومعالجتها. تستخدم الكثير من الأطر والمكتبات (بما في ذلك ASP.NET Core نفسها) هذه الموارد للتعامل مع العديد من الأشياء وراء الكواليس.

الآن دعونا نرى كيف يعمل في الممارسة العملية. إضافة فئة جديدة إلى مجلد ملحقات يسمى EnumExtensions.

قد يبدو الأمر مخيفًا في المرة الأولى التي تنظر فيها إلى الشفرة ، ولكنها ليست معقدة للغاية. دعنا نقطع تعريف الشفرة لفهم كيفية عملها.

أولاً ، حددنا طريقة عامة (طريقة يمكن أن تتلقى أكثر من نوع من الوسيطة ، في هذه الحالة ، ممثلة في إعلان TEnum) التي تتلقى تعدادًا معينًا كوسيطة.

نظرًا لأن التعداد كلمة رئيسية محجوزة في C # ، أضفنا علامة أمام اسم المعلمة لجعلها اسمًا صالحًا.

تتمثل الخطوة الأولى للتنفيذ في هذه الطريقة في الحصول على معلومات النوع (الفئة أو الواجهة أو التعداد أو تعريف البنية) للمعلمة باستخدام طريقة GetType.

بعد ذلك ، تحصل الطريقة على قيمة التعداد المحددة (على سبيل المثال ، كيلوغرام) باستخدام GetField (@ enum.ToString ()).

يبحث السطر التالي عن جميع سمات الوصف المطبقة على قيمة التعداد ويخزن بياناتها في صفيف (يمكننا تحديد سمات متعددة لنفس الخاصية في بعض الحالات).

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

ال ؟. يتحقق عامل التشغيل (مشغل فارغ) إذا كانت القيمة خالية قبل الوصول إلى موقعه.

ال ؟؟ يخبر عامل التشغيل (مشغل لاغية خالية من العناصر) التطبيق بإرجاع القيمة الموجودة على اليسار إذا لم تكن فارغة ، أو القيمة الموجودة على اليمين على خلاف ذلك.

الآن بعد أن أصبح لدينا طريقة امتداد لاستخراج الأوصاف ، فلنهيئ تعييننا بين النموذج والمورد. بفضل AutoMapper ، يمكننا أن نفعل ذلك مع خط إضافي واحد فقط.

افتح الفئة ModelToResourceProfile وقم بتغيير التعليمات البرمجية بهذه الطريقة:

يخبر بناء الجملة هذا AutoMapper باستخدام طريقة الامتداد الجديدة لتحويل قيمة EUnitOfMeasurement إلى سلسلة تحتوي على الوصف الخاص به. بسيط ، أليس كذلك؟ يمكنك قراءة الوثائق الرسمية لفهم بناء الجملة الكامل.

لاحظ أننا لم نحدد أي تكوين تعيين لخاصية الفئة. نظرًا لأننا سبق أن قمنا بتكوين التعيين للفئات ولأن طراز المنتج له خاصية فئة من نفس النوع والاسم ، فإن AutoMapper يعلم ضمنيًا أنه يجب تعيينه باستخدام التكوين ذي الصلة.

الآن دعونا نضيف رمز نقطة النهاية. تغيير رمز ProductsController:

في الأساس ، نفس الهيكل المحدد لوحدة تحكم الفئات.

دعنا نذهب إلى جزء الخدمة. إضافة واجهة IProductService جديدة إلى مجلد "الخدمات" الموجود في طبقة المجال:

يجب أن تدرك أننا نحتاج إلى مستودع قبل تنفيذ الخدمة الجديدة حقًا.

إضافة واجهة جديدة تسمى IProductRepository في المجلد المعني:

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

لا يقوم EF Core ، افتراضيًا ، بتضمين الكيانات ذات الصلة بالنماذج الخاصة بك عند الاستعلام عن البيانات لأنه قد يكون بطيئًا للغاية (تخيل نموذجًا به عشرة كيانات ذات صلة ، وجميع الكيانات ذات الصلة لها علاقاتها الخاصة).

لتضمين بيانات الفئات ، نحتاج إلى سطر إضافي واحد فقط:

لاحظ استدعاء التضمين (p => p.Category). يمكننا وضع سلسلة بناء الجملة هذه لتضمين أكبر عدد ممكن من الكيانات عند الاستعلام عن البيانات. ستقوم EF Core بترجمته إلى صلة عند إجراء الاختيار.

الآن يمكننا تطبيق فئة ProductService بنفس الطريقة التي قمنا بها للفئات:

دعنا نربط التبعيات الجديدة في تغيير فئة بدء التشغيل:

أخيرًا ، قبل اختبار واجهة برمجة التطبيقات ، لنغير فئة AppDbContext لتضمين بعض المنتجات عند تهيئة التطبيق حتى نتمكن من رؤية النتائج:

أضفت منتجين خياليين يربطانهما بالفئات التي نزرعها عند تهيئة التطبيق.

الوقت لاختبار! قم بتشغيل API مرة أخرى وإرسال طلب GET إلى / api / products باستخدام ساعي البريد:

فويلا! هنا منتجاتنا

وهذا كل شيء! تهانينا!

الآن لديك قاعدة حول كيفية إنشاء واجهة برمجة تطبيقات RESTful باستخدام ASP.NET Core باستخدام بنية منفصلة. لقد تعلمت العديد من الأشياء في .NET Framework Framework ، وكيفية التعامل مع C # ، وأساسيات EF Core و AutoMapper والعديد من الأنماط المفيدة التي يجب استخدامها عند تصميم تطبيقاتك.

يمكنك التحقق من التنفيذ الكامل لواجهة برمجة التطبيقات ، التي تحتوي على أفعال HTTP الأخرى للمنتجات ، والتحقق من مستودع Github:

خاتمة

يعد ASP.NET Core إطارًا رائعًا للاستخدام عند إنشاء تطبيقات الويب. لأنه يأتي مع العديد من واجهات برمجة التطبيقات المفيدة التي يمكنك استخدامها لإنشاء تطبيقات نظيفة وقابلة للصيانة. النظر فيه كخيار عند إنشاء التطبيقات المهنية.

لم تتناول هذه المقالة جميع جوانب واجهة برمجة التطبيقات الاحترافية ، لكنك تعلمت جميع الأساسيات. لقد تعلمت أيضًا العديد من الأنماط المفيدة لحل الأنماط التي نواجهها يوميًا.

أتمنى أن تستمتعوا بهذا المقال وآمل أن يكون مفيدًا لك. أقدر ملاحظاتك لفهم كيف يمكنني تحسين هذا.

مراجع للحفاظ على التعلم

.NET الأساسية التعليمية - مستندات Microsoft

وثائق ASP.NET الأساسية - مستندات Microsoft