چهارشنبه, ۱۷ بهمن, ۱۴۰۳ / 5 February, 2025
مجله ویستا
مقدمه ای بر Dot NET Remoting
همانگونه که میدانید وبسرویسها امکانی جهت دسترسی به اشیاء و توابع از طریق شبکه را فراهم میکنند وب سرویسها سیستمی بسیار ساده دارند و از آنها میتوان به عنوان ابزاری جهت برقراری ارتباط بین سیستمهای با Platformهای مختلف استفاده کرد، ولی با تمام قابلیتها و امکاناتی که وبسرویسها دارند این تکنولوژی در برخی موارد به اندازه کافی انعطافپذیر و سریع نیست و لذا پاسخگوی گروه خاصی از نیازها نیست. بزرگترین عاملی که این محدودیت را ایجاد میکند نیاز وب سرویسها به IIS و یا به عبارت دیگر ASP.NET runtime میباشد. جهت فائقآمدن به این مسایل میتوان از Dot NET Remoting استفاده کرد. در واقع Dot NET Remoting هم دقیقاً همان سرویسی را فراهم میکند که وب سرویسها فراهم میکنند ولی دارای ویژگیهای خاصی میباشد که انعطاف و سرعت زیادی نسبت به وب سرویسهای عادی فراهم میکند.
●مقدمه
بهطور کلی اگر ساختار یک وب سرویس، (منظور از وب سرویس در اینجا NET ASP . وبسرویس میباشد) را بررسی کنیم همواره دو جزء در ساختار آن وجود دارد: جزء اول همان کلاسهایی میباشد که درست میکنید. به عبارت دیگر در داخل این کلاسها منطقکاری وبسرویس و توابع عمومی و خصوصی وب سرویس قرار میگیرند و پس از کامپایل، این کلاسها به یک dll تبدیل میشوند. جزء بعدی یک وب سرویس که همواره موردنیاز میباشد برنامهای است که به یک پورت سیستم گوش میدهد و درخواستهای کلاینتها را میگیرد و به جزء اول میدهد و پس از پردازش پاسخ را گرفته و به کلاینت ارسال میکند. در تولید وبسرویسهای عادی تقریباً تمام تمرکز روی جزء اول یعنی کلاسهای آن است. جزء بعدی همان IIS است که کافی است در برخی موارد تنظیمات خاصی روی آن انجام دهیم. با استفاده از NET Remoting. سیستمهایی جهت دسترسی از طریق شبکه فراهم خواهیم کرد که در واقع دو بخش یک وب سرویس در آنها هم وجود دارد، ولی اینبار میتوانیم ازIIS استفاده نکنیم و خودمان برنامه میزبان (منظور برنامهای که به شبکه گوش میدهد و تبادل اطلاعاتی بین کلاینتها و کلاسهای ما را فراهم میکند) را بنویسیم. با این توصیف در واقع میتوان گفت که ASP.NET Web Serviceها نوع سادهشدهای از سیستمهایی هستند که توسط NET Remoting. میتوان تولید کرد چرا که در استفاده از ASP.NETWeb Serviceها مجبور به استفاده از IIS به عنوان برنامه میزبان هستیم. قبل از اینکه شروع به پیادهسازی یک نمونه کامل نماییم، با یک دید کلی اجزاء سیستم پیادهسازی شده توسط NET Remoting را مورد بررسی قرار میدهیم.
●کلاسها
در سمت سرور، remote object همان کلاسهایی میباشند که منطق اصلی کاری را تشکیل میدهند. این کلاسها به صورت یک dll روی سرور قرار میگیرند و توابع public این کلاسها هستند که در نهایت از طریق کلاینتها فراخوانی شده و مورد استفاده قرار میگیرند. Formatter کلاسی است که پاسخهای سرور (مقادیر ارسالی از remote object) را که به صورت یک سری اشیاء میباشند را گرفته و با کدبندی خاصی به یک سری از بایتها تبدیل میکند که مناسب جهت ارسال از طریق شبکه میباشد. همچنین درخواستهایی را هم که کلاینت ارسال میکند از کدبندی خاص آن خارج کرده و تبدیل به یک شیء میکند که قابلفهم برای remote object میباشد. سمت کلاینت نیزformatter دقیقاً همین کار را انجام میدهد ولی جهت عکس. به عملیات تبدیل یک شیء به فرمتی قابلارسال و یا نگهداری که توسط Formatter انجام میشود Serialize و به عکس این عمل Deserialize میگویند. Channel های سمت کلاینت و سرور پروتکل ارتباطی بین کلاینت و سرور و تنظیمات مربوط به آن را تعیین میکنند. اینها در واقع همان برنامه میزبان هستند که در سمت سرور در حالت Listening قرار دارد و در سمت کلاینت به صورت کلاینت میباشند. اما کلاس Proxy که فقط در سمت کلاینت وجود دارد کلاسی است که دقیقاً مانند کلاسهای داخل remote object میباشد. کلاینت قادر به فراخوانی توابع remote object به صورت مستقیم و بیواسطه نیست چرا که remote object روی سیستم دیگری در شبکه قرار دارد و لذا کلاسی تحت عنوان کلی Proxy با همان توابع Public که remote object فراهم میکند در سمت کلاینت ایجاد میشود که از دید کلاینت همانند سایر کلاسهای عادی میباشد؛ ولی وقتی کلاینت تابعی از این کلاس را فراخوانی میکند این تابع یک پیام جهت فراخوانی تابع مشابه خود درremote object ایجاد کرده و ارسال میکند و پس از دریافت پاسخ، نتیجه را در اختیار کلاینت قرار میدهد. توجه داشته باشید که تمام این کلاسها به طور کامل در اختیار شما میباشند و شما میتوانید هر تغییر منطقی موردنیاز را در هر کدام از این کلاسها اعمال کنید و این همان انعطافپذیری کاملی میباشد که NET Remoting . در اختیار شما قرار میدهد. البته تولید تمام این کلاسها احتمالاً برای برخی زیاد هم خوشایند نخواهد بود. چرا که قطعاً زمان زیادی صرف تولید و اشکالزدایی آنها میشود. جهت رفع این مشکل میتوانید از NET. کمک بگیرید چرا که اگر نیازی به قابلیتهای خاص در این سا ختار ندارید. داتنت تمام این کلاسها را با رفتار عادی آنها برای شما تولید میکند؛ مگر دو کلاس که میبایستی شما آنها را تولید کنید. همانطور که حدس زدید یکی کلاس remote object میباشد که رفتار اصلی سیستم شما و قابلیتهایی که میخواهید ارایه دهید در این کلاس قرار دارد و دیگری برنامه یا کلاس میزبان میباشد که قسمت channel را فراهم میکند. در بیشتر موارد هدف استفاده از NET Remoting . بینیاز شدن از IIS یا ASP.NET Runtime میباشد. در ادامه مثال کاملی که در آن به جای IIS از یک برنامه console استفاده میشود را بررسی میکنیم. بهعبارت دیگر برنامه میزبان یک console Application میباشد. در مثال ارایه شده برنامه کلاینت و سرور به صورت console میباشند تا ضمن حفظ سادگی، رفتار دقیق کلاینت و سرور قابل مشاهده باشد. بدیهی است در صورت تمایل میتوانید با انجام چند تغییر جزیی آنها را به برنامههای windows form تبدیل کنید. در ادامه راهنماییهایی هم جهت این تبدیل آورده شده است. (کدهای آماده مثال را میتوانید از سایت ماهنامه شبکه دانلود کنید).
●یک مثال
به مثال زیر توجه کنید. همانطور که اشاره شد Remote Object کلاس یا کلاسهایی است که منطق اصلی موردنظر سیستم در آن قرار دارد. در اینجا یک کتابخانه ساده (dll) یا یک تابع عمومی را به عنوان remote object پیادهسازی میکنیم. همانطور که ملاحظه میکنید از توابع console استفاده شده تا پیامهای مناسبی هنگام فراخوانی سازنده کلاس و یا تابع Hello در خروجی command Prompt چاپ شود. برای تولید این remote object میتوانید یک پروژه از نوع classlibrary درNET. ایجاد کرده و کد مربوط را در کلاسی که به صورت پیشفرضNET . در پروژه ایجاد میکند بنویسید و یا میتوانید کد را در یک فایل متنی ساده تایپ کنید و با پسوند.cs ذخیره کنید و با استفاده از دستور زیر آن را کامپایل کنید: .Csc/t:library/out:My Remote object
dll My Remote object.cs
توجه داشته باشید که remote object از این کلاس ارثبری کند (کلاس Marshal By Refobject قابلیتهای خاصی به کلاسی که از او ارثبری کند میدهد تا آن کلاس جهت ارایه سرویسهای ماندگار در حافظه (lifetime) بهینه شود).
using System;
using System.Runtime.Remoting;
namespace Client
{
class Client
{
static void Main(string[] args)
{
RemotingConfiguration.Configure("Client.exe.config");
MyRemoteObject.MyRemoteObject obj=new MyRemoteObject.MyRemoteObject();
Console.WriteLine(obj.Hello());
Console.ReadLine();
}
}
}
Remote Server
قسمت بعدی پیادهسازی remote server و به عبارت دیگر، برنامه میزبان میباشد، برنامه میزبان و remote object را میتوانید در یک فایل یا اسمبلی پیادهسازی کنید، ولی استفاده از دو فایل متفاوت قابلیت استفاده مجدد (reuse ability) سیستم را بالا میبرد. وظیفه برنامه میزبان، درست کردن یک کانال ارتباطی و گوش دادن به یک پورت سیستم میباشد تا به این وسیله درخواستهای کلاینتها را گرفته و به remote object بدهد. کانال ارتباطی remote server یا برنامه میزبان را میتوان با استفاده از فایل پیکربندی و یا با استفاده از برنامهنویسی تنظیم نمود که هر کدام معایب و مزایای خاصی دارد. وقتی که از فایل پیکربندی (configuration file) استفاده میشود، کدنویسی لازم در برنامه میزبان به حداقل میرسد و همچنین جهت تعویض تنظیمات کانال (به عنوان مثال شماره پورت، یا پروتکل و یا ...) نیازی به دستکاری کدبرنامه و کامپایل مجدد آن ندارید، بلکه فقط کافیاست تنظیمات موردنظر را در فایل پیکربندی انجام دهید. فایل پیکربندی فایلی است با فرمت XML که اطلاعات کانال را در آن قرار میدهند. برنامه میزبان هنگام اجرا، اطلاعات فایل پیکربندی را خوانده و با توجه به تنظیماتی که در آن ثبت شده، کانال ارتباطی را ایجاد میکند، البته در صورتی که از فایل پیکربندی استفاده نکنید نیز مزیت خاصی خواهید داشت و آن تغییر دادن تنظیمات کانال در زمان اجرا توسط برنامه میباشد. در اینجا جهت تولید برنامه میزبان از فایل پیکربندی استفاده خواهیم کرد. اسم فایل پیکربندی را همنام با فایل اجرایی برنامه میزبان بگذارید با پسوند config. در این صورت نام فایل Simpleserver.config خواهد شد. کدهای داخل این فایل به صورت زیر میباشند.
<configuration>
<system.runtime.remoting>
<application name="Client">
<client url="tcp://localhost:۹۰۰۰/Server">
<wellknown
type="MyRemoteObject.MyRemoteObject, MyRemoteObject"
url="tcp://localhost:۹۰۰۰/MyRemoteObject"/>
</client>
<channels>
<channel ref="tcp client" />
</channels>
</application>
</system.runtime.remoting>
</configuration>
همانطور که ملاحظه میکنید اطلاعات کانال و remote object در داخل عنصرsystem.runtime.remoting قرار دارد. عنصر application در فیلد name ، نام سرور را مشخص میکند و در داخل عنصر service مشخصات remote object قرار دارد دو فیلد wellknown و mode مربوط به دستهبندی remote objectها میباشد که در ادامه دستهبندی و انواع مختلف remote objectها را توضیح خواهم داد. فعلاً این دو فیلد را همینگونه بپذیرید. در فیلد type مشخص میشود که این سرویس مربوط به کدام remote object میباشد. در این فیلد به زیرساخت NET Remoting. گفته میشود که در کدام اسمبلی و در چه کلاس و namespaceای در آن اسمبلی remote object قرار دارد. اگر به فایل توجه کنید، مقدار رشتهای فیلد type با کاما (,) دو قسمت شده است قسمت اول namespace و کلاس مربوط به remote object را مشخص میکند و قسمت دوم نام اسمبلی مربوط به remote object را. (درNET. کدهای نوشته شده در بستههای خاصی به نام assembly بستهبندی میشوند. هر اسمبلی دستوراتی به زبان IL و یک سری metadata دارد که NET runtime. با استفاده از این اطلاعات آن را اجرا میکند. توجه داشته باشید که یک اسمبلی میتواند در چند فایل باشد و یا برعکس چند اسمبلی در یک فایل. در اینجا اسمبلی remote object ما در در داخل یک فایل همنام با اسمبلی آن قرار دارد.) در فیلد Object Url آدرسی را مشخص میکنیم که قرار است کلاینتها جهت دسترسی به remote object این آدرس را بدهند. بعداً در فایل پیکربندی برنامه کلاینت خواهید دید که فیلدی با نام Url وجود دارد که آدرس remote object را در آن خواهیم نوشت. در این آدرس پس از مشخص کردن پروتکل و IP آدرس کامپیوتری که برنامه میزبان در آن قرار دارد، مقداری که به فیلد Object Url دادهایم را در آن قرار خواهیم داد. فیلد Object Url میتواند یک URL کامل باشد بدین صورت که remote object در روی سیستم دیگری در وب قرار دارد و یا حتی remote object خود یک وب سرویس میباشد. در اینجا به این فیلد فقط نام اسمبلی remote object را میدهیم و کلاینت هم در فایل پیکربندی خود در فیلد Url از همین نام استفاده خواهد کرد. اگر دقت کرده باشید، متوجه شدهاید که مشخصات remote object در داخل عنصر قرار گرفته است. در واقع جالب است بدانید که در داخل عنصر<>service به هر تعداد remote object و یا به عبارت دیگر سرویس که بخواهیم میتوانیم معرفی کنیم؛ به شرط اینکه به هر کدام از آنها کانال خاصی اختصاص دهیم و بهطور کلی از عهده مدیریت چنین سیستمی برآییم. در چنین حالتی یک برنامه میزبان درخواستهای استفاده از چندین remote object را گرفته و handel میکند. عنصر channels تنظیمات مربوط به کانال یا کانالهای ارتباطی را در خود دارد. در اینجا فقط از یک کانال استفاده خواهیم کرد و به جای ایجاد کانال جدید، از کانالهای تعریفشده در Machine.config استفاده میکنیم. جهت اینکار از فیلد channel ref و سپس ازid کانال تعریف شده در machine.config استفاده میکنیم. فیلد port هم شماره پورتی که برنامه میزبان به آن گوش خواهد داد را مشخص میکند. فایل machine.config فایل XMLای است که تنظیمات ویژهای در سطح سیستم در آن قرار دارد، از جمله کانالهایی که به صورت پیشفرض در آن تعریف شدهاند این فایل در مسیر Microsoft.NET Frameuork CONFIG درSystem Root قرار دارد. با دیدن قسمتی که در آن کانال tcp client تعریف شده است، متوجه میشوید که تعریف کانال جدید در فایل پیکربندی برنامه میزبان کار چندان دشواری نیست. ضمناً علاوه براین کانال پنج کانال دیگر نیز در این فایل تعریف شدهاند که از کانال tcp client در پیادهسازی برنامه کلاینت استفاده خواهیم کرد. با وجود فایل پیکربندی، تمام کاری که برنامه میزبان باید انجام دهد، خواندن محتویات فایل پیکربندی و ایجاد کانال و قرار دادن آن در حالت listining جهت دریافت درخواستهای کلاینتها میباشد. برای انجام تمام این کارها کافیاست یک تابع static که در کلاس Remoting Configuration قرار دارد را فراخوانی کنیم و نام فایل پیکربندی را به عنوان آرگومان به آن بدهیم. برنامه میزبان را به هر صورتی که بخواهید میتوانید پیادهسازی کنید.کد برنامه میزبان به دو صورت زیر میباشد:
//MyRemoteObject.cs
using System;
namespace MyRemoteObject
{
public class MyRemoteObject : System.MarshalByRefObject
{
public MyRemoteObject()
{
Console.WriteLine("Constructor called");
}
public string Hello()
{
Console.WriteLine("Hello called");
return "Hello, .NET Client!";
}
}
}
همانطور که ملاحظه میکنید، این برنامه فقط شامل یک فراخوانی ساده تابع configure میباشد که نام فایل پیکربندی به عنوان آرگومان به آن داده شده است. تابع ()Readline تا زمانی که کاربر کلید Enter را نزده است، منتظر میماند. از این رو برنامه هم در حال اجرا باقی خواهد ماند. پس از کامپایل و درست کردن فایل exe برنامه میزبان توجه داشته باشید که لازم است فایل پیکربندی و dll. مربوط به remote object را که قبلاً ساخته بودید، به مسیری که برنامه میزبان در آن قرار دارد کپی کنید.
●Client Program
برنامه کلاینت قرار است از remote object تولید شده در قسمت قبل استفاده کند. این برنامه هم مانند سرور از یک فایل پیکربندی و یک فایل exe. تشکیل شده است. نام فایل پیکربندی برنامه کلاینت را هم به صورت قبل با اضافه کردن config. به نام فایل exe آن بسازید. این فایل url مربوط به remote object پروتکل و شماره پورت و نام سیستمی را که remote object روی آن قرار دارد مشخص میکند. این فایل به صورت زیر میباشد:
//SimpleServer.cs
using System;
using System.Runtime.Remoting;
namespace Server
{
class SimpleServer
{
static void Main(string[] args)
{
RemotingConfiguration.Configure("SimpleServer.exe.config");
Console.WriteLine("Press return to exit");
Console.ReadLine();
}
}
}
اطلاعات موجود در این فایل مشخص هستند. فقط در مورد channel توجه کنید که اینبار از tcp client تعریف شده در machine config استفاده شده است. همانند برنامه سرور در کلاینت هم با استفاده از تابع configure فایل پیکربندی خوانده شده و تنظیمات لازم انجام میگیرد و در خط بعد یک object از کلاس remote object تعریف شده و تابع ()Hello آن فراخوانی میشود. برای تولید برنامه کلاینت هم مانند قبل میتوانید از .NET استفاده کرده و در صورت تمایل یک برنامه windows form بنویسید و یا در یک فایل متنی ساده کد لازم را بنویسید و از کامپایلر#C برای تولید exe. آن استفاده کنید. توجه داشته باشید که برنامه کلاینت لازم استreference ای به remote object داشته باشد. برای اینکار اگر از NET. استفاده میکنید، با کلیک راست درsolution explorer و انتخاب Add reference ، میتوانید reference را اضافه کنید و اگر از کامپایل خط فرمان #C استفاده میکنید، دستور کامپایل فایل به صورت زیر خواهد بود:
Csc/target:exe/reference My RemoteObjcet.dll
● Simple Client.cs
سؤال مهمی که در اینجا پیش میآید این است که آیا چنانچه بعد از نصب سیستم (کلاینتها و سرور و remote) object بخواهیم تغییر خاصی در منطق کاری remote object (و نه در رابط کاربری آن یعنی توابع عمومی که توسط کلاینتها استفاده میشوند) بدهیم، آیا لازم است نسخه جدید remote object را به تمام سیستمهایی که برنامه کلاینت در آن نصب شده انتقال دهیم؟ بدیهی است که اینکار لازم نیست؛ چرا که اگر اینگونه باشد، استفاده از NET remoting. معنی و مفهوم خود را از دست میدهد. لازم است در هنگام تولید برنامه کلاینت referenceای به remote object در آن ایجاد کنید و برنامه کلاینت را بنویسید. هنگام نصب برنامه کلاینت، remote object هم با آن روی سیستم نصب خواهد شد، ولی در ادامه چنانچه نیاز به ارتقاء remote object داشته باشید، کافی است remote object جدید را روی سرور نصب کنید. کلاینتها به صورت اتوماتیک از remote object جدید استفاده خواهند کرد کد برنامه کلاینت به صورت زیر میباشد: <configuration>
<system.runtime.remoting>
<application name="SimpleServer">
<service>
<wellknown
mode="SingleCall"
type="MyRemoteObject.MyRemoteObject, MyRemoteObject"
objectUri="MyRemoteObject"/>
</service>
<channels>
<channel ref="tcp server" port="۹۰۰۰" />
</channels>
</application>
</system.runtime.remoting>
</configuration>
پس از ساختن فایل exe. برنامه کلاینت سیستم آماده تست میباشد. برای تست ابتدا برنامه سرور را اجرا کنید تا کانال سمت سرور را ساخته و در حالت listening قرار دهد. سپس کلاینت را اجرا کنید. اگر همه چیز تا اینجا درست باشد، سیستم کلاینت مقدار بازگشتی از تابع Hello مربوط به remote object را چاپ خواهد کرد. ضمناً در سمت سرور نیز فراخوانی انجام شده و تابع Hello در پنجره مربوط به سرور اعلان خواهد شد. در اینجا لیست کامل فایلهایی را که برای این سیستم درست کردیم میتوانید ببینید.
توضیحات :کلاس مربوط به Remote object که تابع Hello () در آن میباشد.
My RemoteObject.dll :Assembly
My Remote Object.cs :Source file
My Remote object: Class
توضیحات: برنامه میزبان که کانال ارتباطی سرور را با استفاده از اطلاعات موجود در فایل پیکربندی ایجاد میکند.
SimpleServer.exe: Assembly
Simple Server.cs: Source file
Simple Server: Class
توضیحات: برنامه کلاینت که از سرویس استفاده میکند. این برنامه اطلاعات لازم را از فایل پیکربندی client.exe.confing گرفته و به سرور وصل میشود.
Simple Chient.exe: Assembly
Simple Chient.cs: Source file
SimpleChient: Class
همانطور که قبلاً اشاره شد، remote objectها دارای دستهبندی خاصی میباشند که در این قسمت به صورت مختصر آنها را توضیح میدهیم. به طور کلی remote objectها به دو دسته کلی well-known و client-activated تقسیم میشوند. نوع well-known خود در دو حالت میتواند مورد استفاده قرار گیرد:
Singleton و.SingleCall (مثالی که توضیح داده شد، از نوع well-known و دسته singlecall بود.) نوع well-known همانطور که از نامش هم پیداست، اشیایی شناخته شده هستند که با Url شان آدرسدهی میشوند remote objectهای وwellknown (Single Singleton) Call و به صورت Stateless هستند؛ یعنی هربار که کلاینت تابعی از remote object را فراخوانی میکند، هیچگونه سابقهای از این فراخوانی نگهداری نمیشود و در فراخوانی بعدی نمیتوانید هیچگونه استنادی به فراخوانیهای قبلی بکنید. تفاوت Singleton و Single Call نیز در این است که در حالت Single Call شی remote object در فراخوانی هر تابع ساخته میشود و پس از فراخوانی از بین میرود تا فراخوانی تابع بعدی، ولی در حالت Singleton فقط یک Object ایجاد میشود و تمام فراخوانیها از طریق آن object صورت میپذیرند. لذا میتوان از این حالت جهت اطلاعرسانی عمومی به تمام کلاینتها استفاده کرد. جهت درک نوع singleton ، میتوانید نوع Singleton را مانند متدها یا propertyهای static در کلاس تصور کنید که بین تمام اشیای آن کلاس به اشتراک گذاشته میشوند. البته این مطلب فقط جهت درک singleton میباشد و هیچگونه ارتباطی بین این دو مقوله وجود ندارد. تفاوت عمده remote objectهای clientactivated عمده با نوع قبلی در این است که به صورت statefull هستند و میتوانید به سابقه فراخوانیهای قبلی استناد کنید. البته در استفاده از آنها همیشه به خاطر داشته باشید که مقداردهی به یک property ، نیازمند یک ارتباط شبکهای با remote object میباشد. لذا جهت دستیابی به کارایی قابل قبول، سعی کنید همیشه با حداقل فراخوانیهای متدها وproperty های remote object به هدف خود برسید. اشیا Client activated توسط Url شناسایی نمیشوند، بلکه NET Runtime. هنگام درخواست کلاینت باتوجه به نوع کلاس درخواستی شی موردنظر را تشخیص داده و یک instance از آن میسازد. تعیین نوع remote object و مد آن در فایل پیکربندی انجام میشود و کلیت کارکرد و سیستم NET Remoting. برای تمام این انواع به همان صورت میباشد که توضیح داده شد. لذا در مورد انواع مختلف remote objcetها نگران نباشید. بدیهی است سیستم NET Remoting. بسیار فراتر از آن است که در یک مقاله به تشریح تمام جوانب آن پرداخت. با این وجود در این مقاله تا حد امکان مفاهیم به صورت ساده ارایه شدند و اکنون میتوانید سرویسهای ساده مبتنی بر NET Remoting. را پیادهسازی کنید.
منابع:
۱-MSDN
۲- Wrox Press) C Web Service)
منبع : ماهنامه شبکه
ایران مسعود پزشکیان دولت چهاردهم پزشکیان مجلس شورای اسلامی محمدرضا عارف دولت مجلس کابینه دولت چهاردهم اسماعیل هنیه کابینه پزشکیان محمدجواد ظریف
پیاده روی اربعین تهران عراق پلیس تصادف هواشناسی شهرداری تهران سرقت بازنشستگان قتل آموزش و پرورش دستگیری
ایران خودرو خودرو وام قیمت طلا قیمت دلار قیمت خودرو بانک مرکزی برق بازار خودرو بورس بازار سرمایه قیمت سکه
میراث فرهنگی میدان آزادی سینما رهبر انقلاب بیتا فرهی وزارت فرهنگ و ارشاد اسلامی سینمای ایران تلویزیون کتاب تئاتر موسیقی
وزارت علوم تحقیقات و فناوری آزمون
رژیم صهیونیستی غزه روسیه حماس آمریکا فلسطین جنگ غزه اوکراین حزب الله لبنان دونالد ترامپ طوفان الاقصی ترکیه
پرسپولیس فوتبال ذوب آهن لیگ برتر استقلال لیگ برتر ایران المپیک المپیک 2024 پاریس رئال مادرید لیگ برتر فوتبال ایران مهدی تاج باشگاه پرسپولیس
هوش مصنوعی فناوری سامسونگ ایلان ماسک گوگل تلگرام گوشی ستار هاشمی مریخ روزنامه
فشار خون آلزایمر رژیم غذایی مغز دیابت چاقی افسردگی سلامت پوست