10. تطبيق [SimuPaie] – الإصدار 6 – عميل ASP.NET لخدمة ويب
10.1. بنية التطبيق
نقوم بتطوير بنية العميل/الخادم لاختبار NUnit بالطريقة التالية:
![]() |
في [1]، يتم استبدال الاختبار NUnit بتطبيق الويب من الإصدار 8. يجب أن نتذكر هنا أن هذه البنية تتضمن خادمين ويب غير موضحين:
- خادم ويب يقوم بتشغيل خدمة الويب [S]. سيتم تشغيله في مثيل أول من Visual Web Developer.
- خادم ويب يقوم بتشغيل عميل الويب [1]. وسيتم تشغيله في مثيل ثانٍ من Visual Web Developer.
10.2. مشروع Visual Web Developer للعميل [web]
نقوم بإنشاء مشروع ويب جديد ASP.NET:
![]() |
- في [1]، نختار مشروع ويب بلغة C#
- في [2]، نختار "تطبيق ويب ASP.NET"
- في [3]، نسمي مشروع الويب
- في [4]، نحدد موقعًا لهذا المشروع
- في [5]، تم إنشاء المشروع
نقوم بتعديل بعض خصائص المشروع:
![]() |
- في [1]، اسم التجميع الذي سيتم إنشاؤه
- في [2]، مساحة الأسماء الافتراضية للفئات والواجهات التي سيتم إنشاؤها
لبناء المشروع [pam-v6-client-webservice]، يمكننا استرداد الملفات [Global.asax] و [Default.aspx] من مشروع الويب [pam-v4-3tier-nhibernate-multivues-monopage] ونسخها إلى المشروع [pam-v6-client-webservice]. يتم ذلك باستخدام مستكشف Windows أولاً:
![]() |
- إلى [1]، ومجلد مشروع [pam-v4-3tier-nhibernate-multivues-monopage]
- إلى [2]، ومجلد المشروع [pam-v6-client-webservice] بعد النسخ
- مجلدات [images, pam, ressources]
- ملفات [Global.asax, Global.asax.cs]
- ملفات [Default.aspx, Default.aspx.cs, Default.aspx.designer.cs]
- إلى [3]، في Visual Studio Express، نقوم بعرض جميع ملفات المشروع، لإظهار الملفات المضافة حديثًا
- في [4]، يتم تضمين المجلدات والملفات المضافة في المشروع
![]() |
- في [5] المشروع الجديد [pam-v6-client-webservice]
في هذه المرحلة، يمكن إنشاء المشروع للمرة الأولى [6]. تظهر الأخطاء التالية:
لفهم هذه الأخطاء وتصحيحها، يجب العودة إلى بنية مشروع الويب قيد الإنشاء:
![]() |
المشروع [pam-v6-client-webservice] هو الطبقة [web] [1] في المخطط أعلاه. نرى أن هذه الطبقة تتواصل مع عميل خدمة الويب [C]، وهو عميل سنقوم بإنشائه قريبًا.
- تعود الأخطاء 2 و5 و7 إلى أن كود [pam-v4] كان يشير إلى DLL من الطبقة [metier]، DLL التي أصبحت الآن على جانب الخادم وليس على جانب العميل.
- الأخطاء 1 و 3 لها نفس السبب، ولكن هذه المرة بالنسبة لـ DLL من الطبقة [dao]
- الخطأ 4 ناتج عن أن كود [Global.asax] يستخدم Spring وأن مشروعنا لا يشير إلى DLL من Spring. سنقوم بإضافة هذا الإشارة.
- الخطأ 6 ناتج عن أن الفئة [Employe] محددة في الطبقة [dao] التي لا توجد على جانب العميل.
سيتم حل أخطاء مساحة الاسم 1 و2 و4 و5 و6 و7 من خلال إنشاء عميل C لخدمة الويب. يتم حل الخطأ 3 بإضافة مرجع إلى المشروع على DLL من Spring. يمكننا القيام بما يلي:
![]() |
- في [1]، نضيف مرجعًا إلى مشروع [pam-v6-client-webservice]
- في [4]، تمت إضافة مرجع إلى DLL [Spring.Core] من المجلد [lib].
بعد إضافة هذه الإشارة في Spring، أصبح إنشاء المشروع يظهر خطأً أقل. جميع الأخطاء الأخرى ناتجة عن أسطر كود تشير إلى كائنات في الطبقات [metier] و [dao] الموجودة الآن على الخادم. سنرى أن هذه الكائنات المفقودة سيتم إنشاؤها في عميل [C] لخدمة الويب.
![]() |
قبل إنشاء عميل الخدمة الويب [C]، سنقوم بتعديل مساحة أسماء الفئات المختلفة الموجودة. وهي موجودة حاليًا في مساحة الأسماء [pam-v4]. سنقوم بتغيير مساحة الاسم هذه إلى [pam-v6]. الملفات المعنية هي التالية: Default.aspx.cs، Default.aspx.designer.cs، Global.asax.cs. على سبيل المثال:
....
namespace pam_v6
{
public class Global : System.Web.HttpApplication
{
// --- بيانات التطبيق الثابتة ---
public static Employe[] Employes;
public static IPamMetier PamMetier = null;
....
السطر 2، تم استبدال مساحة الاسم pam_v4 بمساحة الاسم pam_v6.
بالإضافة إلى ذلك، يجب تعديل ترميز الملفات: Default.aspx و Global.asax:
![]() |
يصبح ترميز [Default.aspx] كما يلي:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="pam_v6.PagePam" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
.....
السطر 1، يشير السمة Inherits إلى اسم فئة الملف [Default.aspx.cs]. يتم تغيير مساحة الأسماء.
يصبح ترميز [Global.asax] كما يلي:
<%@ Application Codebehind="Global.asax.cs" Inherits="pam_v6.Global" Language="C#" %>
فيما سبق، يتم تغيير مساحة اسم السمة Inherits.
نقوم الآن بإنشاء عميل [C] لخدمة الويب.
![]() |
لإجراء العمليات التالية، يجب تشغيل خدمة الويب [S] [pam-v5-webservice] في مثيل آخر من Visual Web Developer.
![]() |
- في [1]، نضيف إلى المشروع [pam-v6-client-webservice]، مرجعًا إلى خدمة الويب [pam-v5-webservice]
- في [2]، يتم إضافة URI لخدمة الويب [pam-v5-webservice]. وهو URL لملف WSDL لهذه الخدمة. في بناء خدمة الويب [pam-v5-webservice]، تم توضيح كيفية معرفة عنوان URL هذا.
- في [3]، يُطلب من المساعد استغلال الملف WSDL المشار إليه في [2]
- في [4]، تم اكتشاف خدمة الويب [Service1Soap] وفي [5] الطرق البعيدة التي تعرضها.
- في [6]، يتم تحديد مساحة الأسماء التي سيتم فيها إنشاء فئات وواجهات عميل [C]
- يتم بدء إنشاء العميل [C]
![]() |
- في [1]، العميل الذي تم إنشاؤه. انقر عليه مرتين للوصول إلى محتواه.
- في [2]، في مستكشف الكائنات، يتم عرض الفئات والواجهات الخاصة بمساحة الاسم pam_v6.WsPam. هذه هي مساحة الاسم للعميل الذي تم إنشاؤه.
- في [3]، الفئة التي تنفذ عميل خدمة الويب.
- في [4]، الطرق التي ينفذها العميل [Service1SoapClient]. نجد هنا طريقتي خدمة الويب البعيدة [5] و [6].
- في [2]، نجد صور كيانات الطبقات:
- [metier]: FeuilleSalaire، ElementsSalaire
- [dao]: Employe، Cotisations، Indemnites
فيما يلي، يجب تذكر أن صور الكيانات البعيدة هذه موجودة على جانب العميل وفي مساحة الاسم pam_v6.WsPam.
دعونا نلقي نظرة على الطرق والخصائص التي تعرضها إحداها:
![]() |
- في [1]، يتم تحديد الفئة المحلية [Employe]
- في [2]، نجد خصائص الكيان البعيد [Employe] بالإضافة إلى الحقول الخاصة المستخدمة لاحتياجات الكيان المحلي الخاصة.
دعونا نفحص كود [Global.asax.cs] الذي يحتوي على أخطاء:
![]() |
- تستخدم السطران 3 و 4 مساحات أسماء موجودة على الخادم ولكنها غير موجودة لدى العميل.
- يستخدم السطر 13 فئة [Employe] لم يتم الإعلان عن مساحة الاسم الصحيحة لها
- السطر 14 يستخدم واجهة IPamMetier غير معروفة لدى العميل.
لقد واجهنا بالفعل مشاكل مماثلة في عميل C# الذي تمت دراسته سابقًا.
في البنية:
![]() |
- يتم تنفيذ الطبقة المحلية [metier] بواسطة العميل [C] من النوع pam_v6.WsPam.Service1SoapClient الذي لا ينفذ الواجهة IPamMetier حتى وإن كان يحتوي على طرق تحمل نفس الأسماء.
- الكيانات التي تمت معالجتها (Employe، Indemnites، Cotisations) بواسطة العميل [C] الذي تم إنشاؤه موجودة في مساحة الأسماء pam_v6.WsPam
يتطور كود [Global.asax.cs] على النحو التالي:
using System;
using System.Collections.Generic;
using Pam.Web;
using Spring.Context.Support;
using pam_v6.WsPam;
namespace pam_v6
{
public class Global : System.Web.HttpApplication
{
// --- بيانات التطبيق الثابتة ---
public static Employe[] Employes;
public static Service1SoapClient PamMetier = null;
public static string Msg;
public static bool Erreur = false;
// بدء تشغيل التطبيق
public void Application_Start(object sender, EventArgs e)
{
// تشغيل ملف التكوين
try
{
// إنشاء مثيل الطبقة [metier]
PamMetier = ContextRegistry.GetContext().GetObject("pammetier") as Service1SoapClient;
// قائمة مبسطة بالموظفين
Employes = PamMetier.GetAllIdentitesEmployes();
// تم النجاح
Msg = "Base chargée...";
}
catch (Exception ex)
{
// تسجيل الخطأ
Msg = string.Format("L'erreur suivante s'est produite lors de l'accès à la base de données : {0}", ex);
Erreur = true;
}
}
public void Session_Start(object sender, EventArgs e)
{
// وضع قائمة محاكاة فارغة في الجلسة
List<Simulation> simulations = new List<Simulation>();
Session["simulations"] = simulations;
}
}
}
السطر 24 يقوم بإنشاء مثيل للطبقة [C] باستخدام Spring. يتم إجراء التكوين اللازم لهذا الإنشاء في [web.config]:
<configSections>
<sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
...
</sectionGroup>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
</configSections>
<spring>
<context>
<resource uri="config://spring/objects" />
</context>
<objects xmlns="http://www.springframework.net">
<object id="pammetier" type="pam_v6.WsPam.Service1SoapClient,pam-v6-client-webservice"/>
</objects>
</spring>
في السطر 16، الطبقة [metier] هي مثيل للفئة [pam_v6.WsPam.Service1SoapClient] التي ستوجد في DLL [pam-v6-client-webservice]. نذكر أننا قمنا بتكوين المشروع [pam-v6-client-webservice] لينتج هذا DLL.
لا تزال هناك بعض الأخطاء في [Default.aspx.cs]:
![]() | ![]() |
- السطران 5 و6: لم تعد مساحات الأسماء هذه موجودة. أصبحت الكيانات الآن في مساحة الاسم pam_v6 أو pam_v6.WsPam.
- السطر 98: لم يقم العميل الذي تم إنشاؤه [C] باسترداد الفئة [PamException] من الطبقة [dao]. لم يكن بإمكانه ذلك لأن خدمة الويب لا تعرض هذا الاستثناء. يتم اختيار استبدال PamException بفئته الأصلية Exception.
يصبح الكود:
...
using System.Web.UI.WebControls;
using pam_v6.WsPam;
namespace pam_v6
{
public partial class PagePam : Page
{
...
...
try
{
feuillesalaire = Global.PamMetier.GetSalaire(DropDownListEmployes.SelectedValue, HeuresTravaillées, JoursTravaillés);
}
catch (Exception ex)
{
...
بمجرد تصحيح هذه الأخطاء، يمكننا تشغيل تطبيق الويب:
![]() |
- في [1]، و URL لعميل الويب الخاص بخدمة الويب البعيدة
- في [2]، تم ملء قائمة الموظفين. البيانات التي تحتوي عليها تأتي من خدمة الويب.
ندعو القارئ إلى اختبار هذه النسخة 6 من النسخة 4.

















