تمرين - استخدام خدمة REST مع HttpClient

مكتمل

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

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

ستقوم بتنفيذ هذا التمرين باستخدام بيئة الاختبار المعزولة ل Azure.

تلميح

يمكنك استخدام الزر نسخ لنسخ الأوامر إلى الحافظة. للصق، انقر بزر الماوس الأيمن على سطر جديد في محطة Cloud Shell وحدد Paste، أو استخدم اختصار لوحة المفاتيح Shift + Insert (⌘+V في macOS).

نشر خدمة ويب Parts REST

  1. في نافذة Cloud Shell، قم بتشغيل الأمر التالي لاستنساخ المستودع الذي يحتوي على التعليمات البرمجية لهذا التمرين، بما في ذلك خدمة ويب Parts REST:

    git clone https://github.com/microsoftdocs/mslearn-dotnetmaui-consume-rest-services
    
  2. انتقل إلى مجلد Consume-REST-services :

    cd mslearn-dotnetmaui-consume-rest-services/src
    
  3. قم بتشغيل الأمر التالي لنشر خدمة ويب أجزاء باستخدام بيئة الاختبار المعزولة Azure Cloud Shell. يجعل هذا الأمر الخدمة متاحة من خلال عنوان URL فريد. دون ملاحظة عن عنوان URL هذا عند عرضه. ستقوم بتكوين التطبيق للاتصال بخدمة الويب باستخدام عنوان URL هذا.

    bash initenvironment.sh
    

فحص التعليمات البرمجية لخدمة الويب

إشعار

ستقوم بتنفيذ الجزء المتبقي من هذا التمرين على كمبيوتر التطوير المحلي.

  1. على جهاز الكمبيوتر الخاص بك، افتح نافذة موجه الأوامر وانسخ المستودع لهذا التمرين. التعليمات البرمجية في مستودع net-maui-learn-consume-rest-services .

    git clone https://github.com/microsoftdocs/mslearn-dotnetmaui-consume-rest-services
    

    إشعار

    من الأفضل استنساخ محتوى التمرين أو تنزيله إلى مسار مجلد قصير، مثل C:\dev، لتجنب تجاوز الملفات المنشأة الحد الأقصى لطول المسار.

  2. انتقل إلى المجلد src\webservice\PartsServer في نسخة المستودع، وافتح الحل PartsServer.sln باستخدام Visual Studio أو المجلد في Visual Studio Code. يحتوي هذا الحل على نسخة من التعليمات البرمجية لخدمة الويب التي قمت بنشرها إلى Azure في الإجراء السابق.

  3. في نافذة مستكشف الحلول، قم بتوسيع مجلد Models. يحتوي هذا المجلد على ملفين:

    • Part.cs. تمثل فئة الجزء جزءا كما توفره خدمة ويب REST. تتضمن الحقول معرف الجزء واسم الجزء ونوع الجزء وتاريخ التوفر (عندما تم توفير الجزء لأول مرة) وقائمة بالموردين. ترجع الخاصية Href URI النسبي للجزء؛ يمكن لعميل REST استخدام URI هذا للإشارة إلى هذا الجزء المحدد في خدمة ويب REST. ترجع خاصية الموردين قائمة الموردين للجزء كسلسلة.

    • PartsFactory.cs. تهيئ فئة PartsFactory قائمة الأجزاء التي توفرها الخدمة، باستخدام مجموعة صغيرة من القيم ذات التعليمات البرمجية المضمنة. في العالم الحقيقي، سيتم استرداد هذه البيانات من قاعدة بيانات.

  4. في نافذة مستكشف الحلول، قم بتوسيع مجلد Controllers. يحتوي هذا المجلد على الملفات التالية:

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

    • LoginController.cs. تنفذ فئة LoginController شكلا بسيطا من المصادقة لخدمة الويب. يجب أن يرسل التطبيق طلب HTTP GET إلى وحدة التحكم هذه، والتي ترجع رمزا مميزا للتخويل. يتم استخدام رمز التخويل هذا لمصادقة الطلبات المرسلة إلى PartsController.

    • BaseController.cs. تحتوي فئة BaseController على المنطق المستخدم لمصادقة الطلبات. ترث فئة PartsController من هذه الفئة. إذا حاول العميل استدعاء أساليب في فئة PartsController دون توفير رمز مصادقة صالح، فإن الأساليب ترجع استجابة HTTP 401 (غير مصرح به).

فحص التعليمات البرمجية لتطبيق عميل .NET MAUI

تستخدم هذه الوحدة النمطية .NET 8.0 SDK. تأكد من تثبيت .NET 8.0 عن طريق تشغيل الأمر التالي في الوحدة الطرفية للأوامر المفضلة لديك:

dotnet --list-sdks

يظهر إخراج مشابه للمثال التالي:

6.0.317 [C:\Program Files\dotnet\sdk]
7.0.401 [C:\Program Files\dotnet\sdk]
8.0.100 [C:\Program Files\dotnet\sdk]

تأكد من إدراج إصدار يبدأ بـ 8. إذا لم يتم سرد أي منها أو لم يتم العثور على الأمر، فقم بتثبيت أحدث .NET 8.0 SDK.

  1. أغلق حل PartsServer، وافتح حل PartsClient في المجلد src\client\PartsClient في المستودع المستنسخ. يحتوي هذا الحل على تنفيذ جزئي لتطبيق عميل .NET MAUI يستخدم خدمة ويب PartsServer .

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

    • PartsManager.cs. توفر فئة PartsManager الأساليب التي يستخدمها تطبيق العميل للتفاعل مع خدمة ويب REST. هذه الفئة غير مكتملة حاليا؛ ستضيف التعليمات البرمجية الضرورية أثناء هذا التمرين. عند الاكتمال، يتصل أسلوب GetClient بخدمة ويب REST. يقوم الأسلوب GetAll بإرجاع قائمة بالأجزاء من خدمة ويب REST. يضيف الأسلوب Add جزءا جديدا إلى قائمة الأجزاء التي تديرها خدمة ويب REST. يعدل أسلوب التحديث تفاصيل جزء مخزن بواسطة خدمة ويب REST، ويزيل الأسلوب Delete جزءا.

    • Part.cs. تنمذج فئة الجزء جزءا مخزنا في قاعدة البيانات. يعرض الخصائص التي يمكن للتطبيق استخدامها للوصول إلى حقول PartID و PartName و PartAvailableDate و PartType و PartSuppliers. توفر الفئة أيضا أسلوب أداة مساعدة يسمى SupplierString يمكن للتطبيق استخدامه لاسترداد سلسلة منسقة تحتوي على أسماء الموردين.

  3. في نافذة مستكشف الحلول، قم بتوسيع المجلد Pages. يحتوي هذا المجلد على العلامات والرمز لصفحتين:

    • PartsPage.xaml. تستخدم هذه الصفحة تخطيط CollectionView مع DataTemplate لعرض تفاصيل الأجزاء المتوفرة كقوائم. يستخدم DataTemplate ربط البيانات لتوصيل البيانات المعروضة بالأجزاء التي تم استردادها من خدمة الويب. يمكنك تحديد صف في CollectionView لتحرير جزء في AddPartPage، أو يمكنك تحديد الزر إضافة جزء جديد لإضافة جزء جديد.

    • AddPartPage.xaml. تسمح هذه الصفحة للمستخدمين بإدخال التفاصيل وحفظها لجزء جديد. يمكن للمستخدمين تحديد اسم الجزء ونوع الجزء والمورد الأولي. يتم إنشاء معرف الجزء وتاريخ توفر الجزء تلقائيا.

  4. في نافذة مستكشف الحلول، قم بتوسيع المجلد ViewModels. يحتوي هذا المجلد على فئتين: AddPartViewModel.cs و PartsViewModel.cs. هذه هي نماذج العرض للصفحات الخاصة بها وتحتوي على خصائص ومنطق تحتاج الصفحة إلى عرض البيانات ومعالجتها.

سجل الدخول إلى الخدمة

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

  1. افتح ملف PartsManager.cs في مجلد البيانات .

  2. أضف الحقلين الثابتين BaseAddress وUrl كما هو محدد في قصاصة التعليمات البرمجية التالية إلى فئة PartsManager. استبدل عنوان URL النصي GOES HERE بعنوان URL لخدمة ويب REST التي لاحظتها سابقا:

    public class PartsManager
    {
        static readonly string BaseAddress = "URL GOES HERE";
        static readonly string Url = $"{BaseAddress}/api/";
        ...
    }
    
  3. أضف الحقل التالي إلى الفئة، بعد حقل Url . سيحتفظ هذا الحقل بالرمز المميز للتخويل الذي تم إرجاعه عند تسجيل دخول المستخدم:

    private static string authorizationKey;
    
  4. ابحث عن أسلوب GetClient . يطرح هذا الأسلوب حاليا استثناء NotImplementedException . استبدل التعليمات البرمجية الموجودة في هذا الأسلوب بالتعليمات البرمجية التالية. تنشئ هذه التعليمة البرمجية كائن HttpClient ، ثم ترسل طلبا إلى نقطة نهاية تسجيل الدخول لخدمة ويب REST. يجب أن تستجيب الخدمة برسالة تحتوي على رمز التخويل المميز. قم بإلغاء تسلسل هذا الرمز المميز، وأضفه كعنوان طلب تخويل افتراضي للطلبات اللاحقة المرسلة باستخدام كائن HttpClient :

    private static async Task<HttpClient> GetClient()
    {
        if (client != null)
            return client;
    
        client = new HttpClient();
    
        if (string.IsNullOrEmpty(authorizationKey))
        {                
            authorizationKey = await client.GetStringAsync($"{Url}login");
            authorizationKey = JsonSerializer.Deserialize<string>(authorizationKey);
        }
    
        client.DefaultRequestHeaders.Add("Authorization", authorizationKey);
        client.DefaultRequestHeaders.Add("Accept", "application/json");
    
        return client;
    }
    

تنفيذ عملية GET لاسترداد المعلومات للأجزاء

  1. في ملف PartsManager.cs ، ابحث عن الأسلوب GetAll . هذا أسلوب غير متزامن يقوم بإرجاع قائمة الأجزاء القابلة للتعداد. لم يتم تنفيذ هذا الأسلوب بعد.

  2. في هذا الأسلوب، احذف التعليمات البرمجية التي تطرح استثناء NotImplementedException .

  3. تحقق لمعرفة ما إذا كان الجهاز لديه اتصال بالإنترنت باستخدام Connectivity الفئة . إذا لم يكن الإنترنت موجودا، فسترجع فارغا List<Part>.

    if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet)
        return new List<Part>();
    
  4. استدعاء الأسلوب GetClient لاسترداد كائن HttpClient للعمل معه. تذكر أن GetClient غير متزامن، لذا استخدم عامل الانتظار لالتقاط الكائن الذي تم إرجاعه بواسطة هذا الأسلوب.

  5. استدعاء الأسلوب GetStringAsync للكائن HttpClient وتوفير عنوان URL الأساسي لاسترداد صفيف من الأجزاء من خدمة ويب REST. يتم إرجاع البيانات بشكل غير متزامن كسلسلة JSON.

  6. إلغاء تسلسل سلسلة JSON التي تم إرجاعها بواسطة هذا الأسلوب إلى قائمة كائنات الجزء باستخدام أسلوب JsonSerializer.Deserialize . قم بإعادة هذه القائمة إلى المتصل.

    يجب أن يبدو الأسلوب المكتمل كما يلي:

    public static async Task<IEnumerable<Part>> GetAll()
    {
        if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet)
            return new List<Part>();
    
        var client = await GetClient();
        string result = await client.GetStringAsync($"{Url}parts");
    
        return JsonSerializer.Deserialize<List<Part>>(result, new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true,
            });                     
    }
    
  7. قم بإنشاء التطبيق وتشغيله. عند بدء تشغيل التطبيق، ستظهر صفحة قائمة الأجزاء ويجب أن تظهر قائمة بالأجزاء التي تم استردادها بواسطة أسلوب GetAll . تظهر الصورة التالية التطبيق الذي يعمل على Android:

    A screenshot of the Parts Client app running on Android showing a list of parts.

  8. عند الانتهاء من استعراض البيانات، أغلق التطبيق وارجع إلى Visual Studio أو Visual Studio Code.

تنفيذ عملية POST لإضافة جزء جديد إلى قاعدة البيانات

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

  2. احذف التعليمات البرمجية الموجودة في الأسلوب .

  3. تحقق لمعرفة ما إذا كان الجهاز لديه اتصال بالإنترنت باستخدام Connectivity الفئة . إذا لم يكن الإنترنت موجودا، فسترجع فارغا Part.

    if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet)
        return new Part();
    
  4. إنشاء كائن جزء جديد. قم بتعبئة الحقول بالبيانات التي تم تمريرها:

    • تعيين الحقل PartID إلى سلسلة فارغة. سيتم إنشاء هذا المعرف بواسطة خدمة ويب REST.
    • إنشاء قائمة جديدة للاحتفاظ باسم المورد.
    • تعيين الحقل PartAvailableDate إلى DateTime.Now.
    • الحصول على عميل HTTP من أسلوب GetClient .
    var part = new Part()
    {
        PartName = partName,
        Suppliers = new List<string>(new[] { supplier }),
        PartID = string.Empty,
        PartType = partType,
        PartAvailableDate = DateTime.Now.Date
    };
    
  5. استدعاء الأسلوب GetClient لاسترداد كائن HttpClient للعمل معه.

  6. أنشئ عنصر HttpRequestMessage. يتم استخدام هذا الكائن لنمذجة الطلب الذي يتم إرساله إلى خدمة الويب. ابدأ باستخدام معلمات تشير إلى فعل HTTP الذي يجب استخدامه وعنوان URL لخدمة الويب للاتصال به.

    var msg = new HttpRequestMessage(HttpMethod.Post, $"{Url}parts");
    
  7. تحتاج إلى إرسال حمولة إلى خدمة الويب مع معلومات الجزء المراد إنشاؤها. سيتم تسلسل هذه الحمولة إلى JSON. ستتم إضافة حمولة JSON إلى الخاصية HttpRequestMessage.Content ويتم تسلسلها باستخدام JsonContent.Create الأسلوب .

    msg.Content = JsonContent.Create<Part>(part);
    
  8. الآن أرسل الرسالة إلى خدمة الويب باستخدام الدالة HttpClient.SendAsync . سترجع هذه الدالة كائنا HttpResponseMessage يحتوي على معلومات حول العملية على الخادم. مثل رموز استجابة HTTP والمعلومات التي تم تمريرها مرة أخرى من الخادم.

    var response = await client.SendAsync(msg);
    response.EnsureSuccessStatusCode();
    

    لاحظ أن السابق يستخدم response.EnsureSuccessStatusCode الأسلوب . سيؤدي ذلك إلى ظهور خطأ إذا تم إرجاع أي شيء آخر غير رمز حالة HTTP 2xx.

  9. إذا قامت خدمة الويب بإرجاع معلومات، مثل كائن متسلسل في JSON، يمكنك قراءته من HttpResponseMessage. ثم يمكنك إلغاء تسلسل JSON باستخدام JsonSerializer.Deserialize.

    var returnedJson = await response.Content.ReadAsStringAsync();
    
    var insertedPart = JsonSerializer.Deserialize<Part>(returnedJson, new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true,
            });
    
  10. وأخيرا، قم بإعادة الجزء المدرج الجديد.

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

    A screenshot of the app running after a new part has been added. The new part is at the bottom of the list.

  12. عند الانتهاء من استعراض البيانات، أغلق التطبيق وارجع إلى Visual Studio أو Visual Studio Code.

تنفيذ عملية PUT لتحديث التفاصيل لجزء في قاعدة البيانات

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

  2. حذف التعليمات البرمجية الموجودة.

  3. كما كان من قبل، تحقق من وجود اتصال بالإنترنت.

    if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet)
        return;
    
  4. إنشاء جديد HttpRequestMessage، هذه المرة تحديد عملية PUT وعنوان URL لتحديث الأجزاء.

    HttpRequestMessage msg = new(HttpMethod.Put, $"{Url}parts/{part.PartID}");
    
  5. Content تعيين خاصية HttpRequestMessage باستخدام الدالة JsonContent.Create ومعلمة الجزء التي تم تمريرها إلى الدالة .

    msg.Content = JsonContent.Create<Part>(part);
    
  6. الحصول على عميل HTTP من أسلوب GetClient .

    var client = await GetClient();
    
  7. أرسل الطلب مع HttpClient ثم تأكد من نجاحه.

    var response = await client.SendAsync(msg);
    response.EnsureSuccessStatusCode();
    
  8. قم بإنشاء التطبيق وتشغيله. حدد أحد الأجزاء من القائمة. ستظهر صفحة AddPart، هذه المرة مع الخصائص التي تم ملؤها بالفعل. قم بتحديث ما تريد.

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

    A screenshot of the app running with the first item in the list updated.

    إشعار

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

تنفيذ عملية DELETE لإزالة تفاصيل جزء من قاعدة البيانات

  1. في فئة PartsManager ، ابحث عن الأسلوب Delete . هذا أسلوب غير متزامن يأخذ سلسلة partId ويعيد مهمة.

  2. حذف التعليمات البرمجية الموجودة.

  3. تحقق من وجود اتصال بالإنترنت.

    if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet)
        return;
    
  4. إنشاء كائن جديد HttpRequestMessage . الآن فقط حدد فعل DELETE HTTP وعنوان URL لحذف جزء.

    HttpRequestMessage msg = new(HttpMethod.Delete, $"{Url}parts/{partID}");
    
  5. الحصول على عميل HTTP من أسلوب GetClient .

    var client = await GetClient();
    
  6. إرسال الطلب إلى خدمة الويب. تحقق من النجاح بعد إرجاعه.

    var response = await client.SendAsync(msg);
    response.EnsureSuccessStatusCode();
    
  7. قم بإنشاء التطبيق وتشغيله. حدد جزءا من القائمة ثم حدد حذف في صفحة إضافة جزء . إذا نجحت، فستظهر صفحة قائمة الأجزاء مرة أخرى ولن يكون الجزء الذي حذفته مرئيا.