9. اپلیکیشن [SimuPaie] – نسخهٔ ۵ – ASP.NET / سرویس وب
مطالعهٔ پیشنهادی: مرجع [2]، Introduction to C# 2008، فصل ۱۰ «خدمات وب»
9.1. معماری جدید برنامه
معماری لایهای برنامه Pam در حال حاضر به شرح زیر است:
![]() |
ما آن را به شرح زیر توسعه خواهیم داد:
![]() |
در حالی که در معماری قبلی، لایههای [web]، [metier] و [dao] در یک ماشین مجازی واحد اجرا میشدند.NET، در معماری جدید، لایه [web] در یک ماشین مجازی متفاوت از لایههای [metier] و [dao] اجرا خواهد شد. برای مثال، این حالت زمانی رخ میدهد که لایه [web] روی ماشین M1 باشد و لایههای [metier] و [dao] روی ماشین M2 باشند. این یک معماری کلاینت/سرور است:
- سرور از لایههای [metier] و [dao] تشکیل شده است. از آنجا که این یک سرویس وب است، برای اجرا به وب سرور شمارهٔ ۲ نیاز دارد.
- کلاینت از لایه [web] تشکیل شده است. برای اجرا، به وبسرور شمارهٔ ۱ نیاز دارد.
- کلاینت و سرور از طریق شبکه TCP/IP با استفاده از پروتکل HTTP / SOAP با یکدیگر ارتباط برقرار میکنند. برای این کار، دو لایه جدید باید به معماری اضافه شوند:
- لایه [S] که یک سرویس وب خواهد بود. این سرویس وب درخواستها را از کلاینتهای راه دور دریافت میکند و از لایههای [metier] و [dao] برای انجام آنها استفاده میکند. راههای زیادی برای ساخت یک سرویس TCP/IP وجود دارد. مزیت سرویس وب دوگانه است:
- از پروتکل HTTP استفاده میکند که از طریق فایروالهای سازمانی و دولتی مجاز است.
- این سرویس از یک زیرپروتکل استاندارد HTTP / SOAP استفاده میکند که توسط پلتفرمهای توسعه متعددی مانند .NET، جاوا، PHP، فلکس و غیره پیادهسازی شده است. بدین ترتیب، یک سرویس وب میتواند توسط کلاینتهای .NET، جاوا، PHP و فلکس و غیره «مصرف» (اصطلاح رایج) شود.
- لایه [C] بهعنوان کلاینت برای سرویس وب راه دور عمل خواهد کرد. نقش آن برقراری ارتباط با سرویس وب [S] خواهد بود.
- لایه [S] که یک سرویس وب خواهد بود. این سرویس وب درخواستها را از کلاینتهای راه دور دریافت میکند و از لایههای [metier] و [dao] برای انجام آنها استفاده میکند. راههای زیادی برای ساخت یک سرویس TCP/IP وجود دارد. مزیت سرویس وب دوگانه است:
این معماری جدید را میتوان بدون تلاش زیاد از معماریهای قبلی استخراج کرد:
- لایههای [metier] و [dao] بدون تغییر باقی میمانند
- لایه [web] کمی تغییر میکند، عمدتاً برای ارجاع به انتیتهایی مانند Employe و FeuilleSalaire، که به انتیتهای لایه کلاینت [C] تبدیل شدهاند. این اشیاء مشابه اشیاء در لایههای [metier] یا [dao] هستند، اما به فضاهای نامی متفاوتی تعلق دارند.
- لایه سرور [S] کلاسی است که رابط IPamMetier از لایه [metier] را پیادهسازی میکند. این پیادهسازی به سادگی متدهای متناظر لایه [metier] را فراخوانی میکند. متدهایی که توسط لایه سرور [S] پیادهسازی شدهاند، در اختیار کلاینتهای راه دور قرار میگیرند و آنها قادر خواهند بود این متدها را فراخوانی کنند.
- لایه کلاینت [C] توسط ویژوال استودیو تولید خواهد شد.
اصول معماری جدید به شرح زیر است:
- لایه [web] به ارتباط با لایه [metier] ادامه میدهد، گویی که لایه دوم محلی است. برای دستیابی به این هدف، لایه کلاینت [C] پیادهسازی میکندرابط IPamMetier لایهٔ واقعی [metier] را پیادهسازی میکند و خود را به لایهٔ [web] بهعنوان یک لایهٔ محلی [metier] معرفی میکند. به جز مسئلهٔ فضای نام که قبلاً ذکر شد، لایهٔ [web] بدون تغییر باقی میماند. این مزیت کار کردن با لایهها است. اگر یک برنامهٔ تکلایه ساخته میشد، نیاز به بازنگری بسیار گستردهای داشت.
- لایهٔ کلاینت [C] درخواستها را از لایهٔ [web] به سرویس وب راه دور [S]، بهصورت شفاف برای لایهٔ [web]، فوروارد میکند. این لایه تمام جنبههای «ارتباطات شبکهای» را مدیریت میکند. این لایه پاسخی را از سرویس وب راه دور دریافت میکند و آن را طوری قالببندی میکند که بتواند در قالبی که لایه [web] انتظار دارد، بازگردانده شود.
- در سمت سرور، سرویس وب [S] دستوراتی را از کلاینتهای راه دور خود دریافت میکند. این سرویس دستورات را قالببندی میکند تا متدهای رابط IPamMetier را در لایه [metier] فراخوانی کند. پس از دریافت پاسخ از لایه [metier]، آن را برای ارسال از طریق شبکه به کلاینت [C] قالببندی میکند. لایههای [metier] و [dao] نیازی به تغییر ندارند.
9.2. پروژه Visual Web Developer برای سرویس وب
ما در حال ایجاد یک پروژه جدید با استفاده از Visual Web Developer هستیم:
![]() |
- در [1]، یک پروژه وب C# را انتخاب میکنیم
- در [2]، «Web Service Application ASP.NET» را انتخاب میکنیم
- در [3]، به پروژه وب نامی میدهیم
- در [4]، ما یک مکان برای این پروژه مشخص میکنیم
![]() |
- در [1]، پروژهٔ تولیدشده. این یک پروژهٔ وب استاندارد است، با جزئیات زیر:
- ما مشخص کردهایم که پروژه از نوع «سرویس وب» است. یک سرویس وب صفحات وب HTML را برای مشتریان خود ارسال نمیکند، بلکه دادهای را در قالب XML ارسال میکند. در نتیجه، صفحهای که معمولاً تولید میشود، یعنی [Default.aspx]، تولید نشده است.
- در [2]، فایلی با نام [Service1.asmx] با محتوای زیر ایجاد شد:
<%@ WebService Language="C#" CodeBehind="Service1.asmx.cs" Class="pam_v5_webservice.Service1" %>
- (ادامه)
- - تگ WebService نشان میدهد که [Service.asmx] یک سرویس وب است
- - ویژگی CodeBehind مکان کد منبع این سرویس وب را مشخص میکند
- - ویژگی Class نام کلاسی را که سرویس وب را در کد منبع پیادهسازی میکند، مشخص مینماید.
کد منبع [Service.asmx.cs] برای سرویس وب پیشفرض به شرح زیر است:
using System.Web.Services;
namespace pam_v5_webservice
{
/// <summary>
/// توضیح خلاصه سرویس1
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// برای اینکه این سرویس وب از طریق اسکریپت با استفاده از ASP.NET AJAX فراخوانی شود، علامتهای کامنت را از خط زیر حذف کنید.
// [System.Web.Script.Services.ScriptService]
public class Service1 : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
}
}
- خط ۸: حاشیهنویسی WebService که تضمین میکند کلاس Service1 در خط ۱۳ بهعنوان یک سرویس وب در دسترس قرار گیرد. یک سرویس وب به یک فضای نام تعلق دارد تا از نامگذاری یکسان دو سرویس وب در هر نقطهای از جهان جلوگیری شود. ما در مرحله بعد باید این فضای نام را تغییر دهیم.
- خط ۱۳: کلاس Service1 از کلاس WebService در فریمورک .NET مشتق شده است.
- خط ۱۶: تگ WebMethod تضمین میکند که متدی که به این شکل تگ شده است در معرض کلاینتهای راه دور قرار گیرد و آنها بتوانند آن را فراخوانی کنند.
- خطوط ۱۷–۲۰: متد HelloWorld یک متد نمایشی است. ما بعداً آن را حذف خواهیم کرد. این متد به ما امکان میدهد تستهای اولیه را انجام دهیم و با ابزارهای ویژوال استودیو و همچنین برخی جنبههای سرویسهای وب آشنا شویم.
![]() |
- در [1]، سرویس وب [Service.asmx] را اجرا میکنیم
![]() |
- VS Web Developer سرور وب داخلی خود را راهاندازی کرده و در یک پورت تصادفی، در این مورد 1599، در حال گوش دادن است. سپس URL [2] از سرور وب درخواست شد. این URL برای یک صفحه آزمایشی سرویس وب است.
- در [3]، لینکی وجود دارد که به شما امکان مشاهده فایل توصیف سرویس وب را میدهد. این فایل که به دلیل پسوند (.wsdl) خود با نام WSDL (زبان توصیف WebService) شناخته میشود، یک فایل XML است که متدهای ارائه شده توسط سرویس وب را توصیف میکند. از همین فایل WSDL است که کلاینتها میتوانند مشخص کنند:
- فضای نام سرویس وب
- فهرست متدهای ارائه شده توسط سرویس وب
- پارامترهای مورد انتظار هر یک از آنها
- پاسخ بازگرداندهشده توسط هر یک از آنها
- در [4]، تنها متدی که توسط سرویس وب ارائه شده است .
![]() |
- در [5]، محتویات فایل WSDL که از طریق لینک [3] به دست آمده است. توجه داشته باشید URL و [6]. کاربران سرویس وب باید از این موارد آگاه باشند.
![]() |
- در [7]، صفحهای که از طریق لینک [4] به آن دسترسی پیدا میشود، امکان فراخوانی متد [HelloWorld] سرویس وب را فراهم میکند
- در [8]، نتیجه حاصل یک پاسخ XML است. به URL و [9] متد توجه کنید.
مطالعه صفحات قبلی به درک نحوه فراخوانی یک متد سرویس وب و نوع پاسخی که بازمیگرداند کمک میکند. این امر توسعه کلاینتهایی را که قادر به ارتباط با سرویس وب هستند، ممکن میسازد. اکثر ابزارهای IDE امروزی امکان تولید خودکار این کلاینت (HTTP) را فراهم میکنند و بدین ترتیب توسعهدهنده را از نوشتن آن بینیاز میسازند. این موضوع بهویژه در مورد ویژوال استودیو اکسپرس صادق است.
قبل از ادامه این پروژه، فضای نامی (namespace) پیشفرض هنگام تولید کلاسها را تغییر خواهیم داد:
![]() |
وقتی ویژگیهای پروژه را انتخاب میکنیم (کلیک راست روی پروژه / Properties)، نام پروژه را به عنوان [1] و فضای نام پیشفرض آن را به عنوان l'assembly مشاهده میکنیم.
پس از انجام این کار،
- در [Service1.asmx.cs]، فضای نام کلاس را به این صورت تغییر میدهیم:
using System.Web.Services;
namespace pam_v5
{
...
public class Service1 : System.Web.Services.WebService
{
...
}
}
- در [Service.asmx]، ما همچنین فضای نامی مورد استفاده برای کلاس [Service1] را نیز تغییر میدهیم (کلیک راست / مشاهده منبع):
<%@ WebService Language="C#" CodeBehind="Service1.asmx.cs" Class="pam_v5.Service1" %>
بیایید به معماری برنامهٔ خود بازگردیم:
![]() |
- لایه [S] سرویس وب است. این لایه به سادگی متدهای لایه [metier] را برای کلاینتهای راه دور در دسترس قرار میدهد. این همان لایهای است که در حال حاضر در حال ساخت آن هستیم.
- لایه [C]، کلاینت سرویس وب HTTP است. این لایه است که لایههای IDE قادر به تولید خودکار آن هستند.
- لایه [web] لایه [C] را بهعنوان یک لایه محلی [metier] میبیند، اگر تضمین کنیم که لایه [C] پیادهسازی میکندرابط لایهٔ راه دور [metier].
در زیر میبینیم که سرویس وب ما:
- روشهای لایه [metier] را در دسترس قرار دهد
- با لایهٔ [dao] ارتباط برقرار کند، که به نوبهٔ خود با لایهٔ [metier] ارتباط برقرار خواهد کرد.
بنابراین پروژه باید از لایههای [metier] و [dao]، DLL را استفاده کند. این به شرح زیر تکامل مییابد:
![]() |
- به [1]؛ ارجاعات به پروژه اضافه میشوند
- در [2]، فایلهای معمول DLL از پوشه [lib] انتخاب میشوند. باید اطمینان حاصل شود که ویژگی «نسخه محلی» (Local copy) همه آنها روی True تنظیم شده باشد. فایلهای منتخب DLL آنهایی هستند که لایههای [metier] و [dao] را با پشتیبانی NHibernate پیادهسازی میکنند.
یک برنامه وب از نوع «سرویس وب ASP.NET» ممکن است یک کلاس برنامه جهانی «Global.asax» داشته باشد، درست مانند یک برنامه وبسایت سنتی «ASP.NET». ما مزایای چنین کلاسی را دیدهایم:
- این کلاس هنگام راهاندازی برنامه ایجاد شده و در حافظه باقی میماند
- بنابراین میتواند دادههایی را که بین همه کلاینتها مشترک است و فقط قابل خواندن (read-only) هستند، ذخیره کند. در برنامه ما، مانند نمونههای قبلی، این کلاس فهرست سادهشده کارمندان را ذخیره خواهد کرد. این کار باعث میشود که هر بار یک کلاینت این فهرست را درخواست میکند، نیازی به بازیابی آن از پایگاه داده نباشد.
![]() |
- در [1]، روی پروژه کلیک راست کنید
- در [2]، گزینه [Ajouter un nouvel élément] را انتخاب کنید
- در [3]، [Classe d'application globale] را انتخاب کنید
- در [4]، فایل [Global.asax] به پروژه اضافه شده است
محتویات فایل [Global.asax] به شرح زیر است:
<%@ Application Codebehind="Global.asax.cs" Inherits="pam_v5.Global" Language="C#" %>
محتویات فایل [Global.asax.cs] به شرح زیر است:
using System;
namespace pam_v5
{
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
}
...
}
}
در روش Application_Start چه کاری باید انجام دهیم؟ دقیقاً همانند برنامههای وب قبلی. بیایید به معماری برنامه بازگردیم و کلاس [Global] را در آن قرار دهیم:
![]() |
در نمودار بالا،
- کلاس [Global] هنگام راهاندازی سرویس وب ایجاد میشود. این کلاس تا زمانی که سرویس وب فعال است در حافظه باقی میماند.
- کلاس [Global] لایههای [metier] و [dao] را در متد [Application_Start] خود ایجاد میکند.
- برای بهبود عملکرد، کلاس [Global] فهرست سادهشده کارمندان را در یک فیلد داخلی ذخیره میکند. این کلاس فهرست کارمندان را از این فیلد بازمیگرداند.
- سرویس وب برای هر درخواست مشتری نمونه سازی میشود. پس از رسیدگی به آن درخواست، آزاد میشود. این کلاس مستقیماً با لایه [metier] ارتباط برقرار نمیکند، بلکه با کلاس [Global] ارتباط برقرار میکند. این کلاس رابط لایه [metier] را پیادهسازی خواهد کرد.
کلاس [Global] مشابه کلاسی است که قبلاً برای برنامههای کاربردی قبلی ایجاد شده است:
using System;
using Pam.Dao.Entites;
using Pam.Metier.Entites;
using Pam.Metier.Service;
using Spring.Context.Support;
namespace pam_v5
{
public class Global : System.Web.HttpApplication
{
// --- دادههای ثابت برنامه ---
public static Employe[] Employes;
public static IPamMetier PamMetier = null;
protected void Application_Start(object sender, EventArgs e)
{
// نمونه سازی لایه [metier]
PamMetier = ContextRegistry.GetContext().GetObject("pammetier") as IPamMetier;
// بازیابی فهرست سادهشده کارمندان
Employes = PamMetier.GetAllIdentitesEmployes();
}
// فهرست سادهشده کارمندان
static public Employe[] GetAllIdentitesEmployes()
{
return Employes;
}
// حقوق یک کارمند
static public FeuilleSalaire GetSalaire(string SS, double heuresTravaillées, int joursTravailles)
{
return PamMetier.GetSalaire(SS, heuresTravaillées, joursTravailles);
}
}
}
کلاس [Global] رابط [IPamMetier] را پیادهسازی میکند، اما این موضوع به صراحت در اعلان آن ذکر نشده است:
public class Global : System.Web.HttpApplication, IPamMetier
در واقع، متدهای GetAllIdentitesEmployes (خط 24) و GetSalaire (خط 30) استاتیک هستند، در حالی که متدهای رابط IPamMetier استاتیک نیستند. در نتیجه، کلاس Global نمیتواند رابط IPamMetier را پیادهسازی کند. علاوه بر این، امکان اعلام متدهای GetAllIdentitesEmployes و GetSalaire به عنوان غیرثابت (non-static) وجود ندارد. این به آن دلیل است که به آنها از طریق نام کلاس دسترسی پیدا میشود و نه از طریق یک نمونه از کلاس.
- خط ۱۵: متد Application_Start مشابه متد کلاسهای [Global] بررسیشده در نسخههای قبلی است. این متد لایه [metier] (خط ۱۸) را نمونه سازی میکند و سپس آرایه کارمندان از خط ۱۲ را مقداردهی اولیه میکند.
- خط 24: متد GetAllIdentitesEmployes به سادگی آرایه کارمندان از خط 12 را بازمیگرداند. به همین دلیل در ابتدای برنامه ذخیره شده بود.
- خط ۳۰: متد GetSalaire متد با همین نام را در لایه [metier] فراخوانی میکند.
برای نمونهسازی لایه [metier] (خط ۱۸)، کلاس [Global] از فریمورک Spring استفاده میکند. این کار توسط فایل [Web.config] پیکربندی میشود که با پروژه قبلی یکسان است: این فایل، Spring و NHibernate را برای ایجاد لایههای [metier] و [dao] سرویس وب پیکربندی میکند.
بیایید به معماری برنامهٔ کلاینت/سرور خود بازگردیم:
![]() |
در سمت سرور، تنها کاری که باقی مانده نوشتن خود سرویس وب [S] است. با بازگشت به معماری برنامه:
![]() |
میتوانیم ببینیم که در سمت سرور، تمام لایههایی که قبل از لایه [metier] قرار دارند، رابط آن، IPamMetier را پیادهسازی میکنند. این امر اجباری نیست، اما رویکردی است که منطقی به نظر میرسد. این استدلال را میتوان در سمت کلاینت، برای کلاینت [C] سرویس وب [S] نیز به کار برد. بنابراین، تمام لایههایی که لایه [web] را از لایه [metier] جدا میکنند، سپس رابط IPamMetier را پیادهسازی میکنند. بنابراین میتوان گفت که ما به یک برنامه سهلایه بازگشتهایم:
- لایهٔ ارائه [web] [1]
- لایههای [metier] و [2]
- لایه دسترسی به داده [3]
پیادهسازی سرویس وب [Service1.asmx.cs] میتواند به صورت زیر باشد:
using System.Web.Services;
using Pam.Dao.Entites;
using Pam.Metier.Entites;
using Pam.Metier.Service;
namespace pam_v5
{
[WebService(Namespace = "http://st.istia.univ-angers.fr/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class Service1 : System.Web.Services.WebService, IPamMetier
{
// فهرست شناسهٔ تمام کارمندان
[WebMethod]
public Employe[] GetAllIdentitesEmployes()
{
return Global.GetAllIdentitesEmployes();
}
// ------- محاسبه حقوق
[WebMethod]
public FeuilleSalaire GetSalaire(string ss, double heuresTravaillees, int joursTravailles)
{
return Global.GetSalaire(ss, heuresTravaillees, joursTravailles);
}
}
}
- خط ۸: کلاس با ویژگی [WebService] علامتگذاری شده و ما یک نام به فضای نام سرویس وب اختصاص میدهیم
- خط ۱۱: کلاس [Service1] از کلاس [WebService] ارث میبرد و رابط [IPamMetier] را پیادهسازی میکند
- خطوط ۱۵ و ۲۲: هر متد کلاس با ویژگی [WebMethod] علامتگذاری شده است تا برای کلاینتهای راه دور قابل دسترس باشد. به طور پیشفرض، تمام متدهای عمومی یک سرویس وب قابل دسترس هستند. بنابراین ویژگیهای موجود در خطوط ۱۵ و ۲۲ در اینجا اختیاری هستند. برای پیادهسازی رابط [IPamMetier]، هر متد به سادگی متد همنام را در کلاس [Global] فراخوانی میکند.
اکنون آماده اجرای سرویس وب هستیم:
![]() |
- در [1]، پروژه دوباره تولید میشود
- در [2]، سرویس وب [Service1.asmx] را انتخاب کرده و آن را در مرورگر [3] نمایش میدهیم.
- در [4]، صفحه وب نمایش داده میشود. این صفحه متدهای سرویس وب را نشان میدهد.
![]() |
- در [4]، ما لینک [GetAllIdentitesEmployes] را دنبال میکنیم و به [5]، صفحه آزمایشی این روش، میرسیم.
- در [6]، URL برای این روش
- در [7]، دکمه [Appeler] برای آزمایش این روش. این روش به هیچ پارامتری نیاز ندارد.
- در [8]، نتیجه XML بازگرداندهشده توسط سرویس وب. در این میان، تنها ویژگیهای SS، Nom، Prenom از اشیاء Employe مرتبط هستند، زیرا متد [GetAllIdentitesEmployes] تنها این ویژگیها را درخواست میکند. با این حال، این متد آرایهای از اشیاء Employe را بازمیگرداند. در [8] میبینیم که ویژگیهای عددی Id و Version در جریان XML بازگشتی گنجانده شدهاند، اما ویژگیهایی با مقدار null گنجانده نشدهاند: Adresse، Ville، CodePostal، Indemnites.
ما یک سرویس وب فعال داریم. اکنون قصد داریم یک کلاینت C# برای آن بنویسیم. برای این کار، به URI از فایل WSDL سرویس وب نیاز داریم. این را از صفحهای که هنگام اجرای [Service.asmx] در ابتدا نمایش داده میشود، بهدست میآوریم:
![]() |
- در [1]، URI از سرویس وب
- به [2]، لینکی که به فایل آن WSDL منتهی میشود
- به [3]، مقدار آن لینک
9.3. پروژهٔ C# برای کلاینت NUnit سرویس وب
ما در حال ایجاد یک پروژه C# (با استفاده از Visual C#، نه Visual Web Developer) برای کلاینت سرویس وب هستیم. این یک کلاینت آزمایشی خواهد بود، NUnit. بنابراین پروژه از نوع «کتابخانه کلاس» خواهد بود.
![]() |
- در [1]، ما یک پروژه C# از نوع «کتابخانه کلاس» ایجاد میکنیم
- در [2]، پروژه را نامگذاری میکنیم
- در [3]، پروژه. ما [Class1.cs] را حذف میکنیم.
- در [4]، پروژه جدید.
![]() |
- در ویژگیهای پروژه، در برگه [Application] [5]، فضای نام پروژه را تنظیم میکنیم. هر کلاسی که توسط IDE تولید شود، در این فضای نام قرار خواهد گرفت.
ما پروژه جدیدمان را در مکانی که انتخاب میکنیم ذخیره میکنیم:
پس از انجام این کار، کلاینت سرویس وب راه دور را ایجاد میکنیم. برای درک اینکه قرار است چه کاری انجام دهیم، باید به معماری کلاینت/سرور فعلی که در حال ساخت است بازگردیم:
![]() |
IDE لایه کلاینت [C] را از URI در فایل WSDL سرویس وب [S] تولید خواهد کرد. شایان ذکر است که URI از این فایل قبلاً ذکر شده بود. ما از به شرح زیر ادامه میدهیم:
![]() |
- به [1]، روی شاخه References کلیک راست کرده و یک مرجع سرویس اضافه کنید
- به [2]، با مشخص کردن URL فایل WSDL برای سرویس وب یادداشتشده قبلاً. اگر این سرویس از قبل در حال اجرا نیست، باید از قبل راهاندازی شود.
- در [3]، کشف سرویس وب را از طریق فایل WSDL آن درخواست کنید
- در [4]، وبسرویس کشفشده
- در [5]، متدهای ارائه شده توسط سرویس وب.
- در [6]، فضای نامی که میخواهید کلاسها و رابطهای کلاینت تولیدشده را در آن قرار دهید.
- جادوگر را تأیید کنید
![]() |
- در [1]، کلاینت تولیدشده . برای مشاهدهٔ محتویات آن روی آن دوبار کلیک کنید.
- در [2]، در Object Explorer، کلاسها و رابطهای فضای نام Client.WsPam نمایش داده میشوند. این فضای نام کلاینت تولید شده است.
- در [3]، کلاسی که مشتری سرویس وب را پیادهسازی میکند.
- در [4]، متدهایی که توسط کلاینت [Service1SoapClient] پیادهسازی شدهاند. اینها شامل دو متد سرویس وب راه دور هستند: [5] و [6].
- در [2]، تصاویر اجزای لایه نمایش داده میشوند:
- [metier]: FeuilleSalaire, ElementsSalaire
- [dao]: Employe, Cotisations, Indemnites
در ادامه، مهم است به خاطر داشته باشیم که این تصاویر از اشیاء راه دور در سمت کلاینت و در فضای نام PamV5Client.WsPam قرار دارند.
بیایید روشها و ویژگیهای ارائه شده توسط یکی از آنها را بررسی کنیم:
![]() |
- در [1]، کلاس محلی [Employe] انتخاب میشود
- در [2]، ما ویژگیهای موجوده دور [Employe] و همچنین فیلدهای خصوصی را که برای نیازهای خاص موجوده محلی استفاده میشوند، مییابیم.
بیایید به برنامهٔ C# خود بازگردیم. یک کلاس آزمایشی به نام NUnit اضافه خواهیم کرد:
![]() |
- در [1]، کلاس [NUnit] اضافه شده است. کلاس [NUnit] به فریمورک NUnit نیاز دارد و بنابراین در آن به DLL ارجاع داده شده است. در اینجا فرض میکنیم که چارچوب NUnit روی ایستگاه کاری نصب شده است (http://nunit.org/).
- در [2]، یک ارجاع به پروژه اضافه کنید
- در زبانه [3]. در زبانه NET که فایلهای DLL ذخیره شده روی رایانه را فهرست میکند، [4] را انتخاب میکنیم، DLL و [nunit.framework] (حداقل نسخه 2.4.6).
علاوه بر این، ما از Spring برای ایجاد نمونهٔ کلاینت محلی [C] برای سرویس وب [S] استفاده خواهیم کرد:
![]() |
مرجع Spring DLL را میتوان به همان روشی که برای فریمورک NUnit انجام میشود، اضافه کرد، به شرطی که فایلهای DLL قبلاً روی ماشین نصب شده باشند (http://www.springframework.net/download.html).
ما رویکرد متفاوتی را در پیش میگیریم. ما از پوشه [lib] پروژههای قبلی استفاده میکنیم که حاوی فایلهای DLL مورد نیاز Spring بود، و ارجاع Spring را به پروژه اضافه میکنیم:
![]() |
بیایید نگاهی دیگر به معماری کلاینت فعلی در حال توسعه بیندازیم:
![]() |
در بالا، میتوانیم ببینیم که کلاینت تست [1] با یک لایه توسعهیافته [metier] [2] تعامل دارد. این لایه همان متدهای لایه راه دور [metier] را دارد. بنابراین میتوانیم از کلاس آزمایشی که هنگام آزمایش لایه [metier] در پروژه C# [pam-metier-dao-nhibernate] با آن مواجه شدیم، استفاده کنیم:
using NUnit.Framework;
using Pam.Dao.Entites;
using Pam.Metier.Entites;
using Pam.Metier.Service;
using Spring.Context.Support;
namespace Pam.Metier.Tests {
[TestFixture()]
public class NunitTestPamMetier : AssertionHelper {
//لایه [metier] برای تست
private IPamMetier pamMetier;
// سازنده
public NunitTestPamMetier() {
// نمونهسازی لایه [dao]
pamMetier = ContextRegistry.GetContext().GetObject("pammetier") as IPamMetier;
}
[Test]
public void GetAllIdentitesEmployes() {
//بررسی تعداد کارکنان
Expect(2, EqualTo(pamMetier.GetAllIdentitesEmployes().Length));
}
[Test]
public void GetSalaire1() {
//محاسبه حقوق و دستمزد
FeuilleSalaire feuilleSalaire = pamMetier.GetSalaire("254104940426058", 150, 20);
// چکها
Expect(368.77, EqualTo(feuilleSalaire.ElementsSalaire.SalaireNet).Within(1E-06));
// برگه پرداخت برای کارمند وجود ندارد
bool erreur = false;
try {
feuilleSalaire = pamMetier.GetSalaire("xx", 150, 20);
} catch (PamException) {
erreur = true;
}
Expect(erreur, True);
}
}
}
چند تغییر باید اعمال شود:
- در خط ۱۸، ما لایه [metier] را با استفاده از فریمورک Spring نمونهسازی میکنیم. کلاس در هر دو مورد یکسان نیست. در اینجا، لایه محلی [metier] یک نمونه از کلاس [PamV5Client.WsPam.Service1SoapClient] است، کلاسی که توسط IDE تولید شده است. بنابراین، Spring در فایل [app.config] پروژه C# به صورت زیر پیکربندی شده است:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<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="PamV5Client.WsPam.Service1SoapClient, pam-v5-client-csharp-webservice"/>
</objects>
</spring>
<system.serviceModel>
...
- در خط ۱۶ بالا، شیء [pammetier] یک نمونه از کلاس [PamV5Client.WsPam.Service1SoapClient] است که در اسمبلی [pam-v5-client-csharp-webservice] قرار دارد. برای یافتن اولین اطلاعات، کافی است به تعریف کلاس [Service1SoapClient] در Object Explorer (بخش 9.3) بازگردید:
![]() |
- در [2]، کلاس پیادهسازی لایه محلی [metier]، و در [1] فضای نام آن
- به [3]؛ در ویژگیهای پروژه، نام assembly—دومین اطلاعات مورد نیاز برای پیکربندی شیء Spring [pammetier].
بیایید به کد ایجاد لایه محلی [metier] در [NUnit.cs] بازگردیم:
//لایه [metier] برای آزمایش
private IPamMetier pamMetier;
// سازنده
public NunitTestPamMetier() {
// نمونهٔ لایهٔ [dao]
pamMetier = ContextRegistry.GetContext().GetObject("pammetier") as IPamMetier;
}
در خط ۷، لایهٔ راه دور [metier] از نوع IPamMetier بود. در اینجا، لایهٔ [metier] از نوع [Service1SoapClient] است:
public class Service1SoapClient : System.ServiceModel.ClientBase<Service1Soap>
میتوانیم ببینیم که کلاس Service1SoapClient رابط IPamMetier را پیادهسازی نمیکند، هرچند متدهایی با همان نامها را ارائه میدهد. بنابراین باید نمونهسازی لایه محلی [metier] را به صورت زیر بنویسیم:
//لایه [metier] برای آزمایش
private Service1SoapClient pamMetier;
// سازنده
public NunitTestPamMetier() {
// مثال لایه [metier]
pamMetier = ContextRegistry.GetContext().GetObject("pammetier") as Service1SoapClient;
}
یک تغییر دیگر که باید انجام شود:
[Test]
public void GetSalaire1() {
...
try {
feuilleSalaire = pamMetier.GetSalaire("xx", 150, 20);
} catch (PamException) {
erreur = true;
}
Expect(erreur, True);
}
کد بالا در خط ۶ از نوع PamException استفاده میکند که در سمت کلاینت وجود ندارد. ما آن را با کلاس والدش، یعنی نوع Exception، جایگزین خواهیم کرد.
[Test]
public void GetSalaire1() {
...
try {
feuilleSalaire = pamMetier.GetSalaire("xx", 150, 20);
} catch (Exception) {
erreur = true;
}
Expect(erreur, True);
}
در نهایت، فضاهای نام واردشده دیگر یکسان نیستند:
using System;
using PamV5Client.WsPam;
using NUnit.Framework;
using Spring.Context.Support;
پس از انجام این کار، پروژه «کتابخانه کلاس» قابل تولید است. خروجی زیر ایجاد میشود:
![]() |
- در [1]، پوشه [bin/Release] پروژه C#
- وارد [2]، و فایل DLL از پروژه
سپس تست NUnit توسط فریمورک NUnit اجرا میشود (پایه MySQL و dbpam_nhibernate باید برای تست فعال باشند):
- در [3] و [4]، DLL و [2] در برنامهٔ آزمایشی NUnit بارگذاری میشوند
![]() |
- در [5]، کلاس تست انتخاب و اجرا میشود [6]
- در [7]، نتایج یک تست موفق
اکنون یک سرویس وب کاربردی داریم.






























