اندازهی قلم متن
تخمین مدت زمان مطالعهی مطلب:
دو دقیقه
در WCF به صورت پیش فرض متدها به صورت Request-Response هستند. این بدین معنی است که هر زمان درخواستی از سمت کلاینت به سرور ارسال شود تا زمانی که پاسخی از سمت سرور به کلاینت برگشت داده نشود، کلاینت منتظر خواهد ماند. برای مثال:
پروژه ای از نوع Wcf Service App میسازیم و یک سرویس با یک متد که خروجی آن نیز void است خواهیم داشت. به صورت زیر:
پیاده سازی Contract بالا:
در متد Wait، به مدت یک دقیقه اجرای برنامه سمت سرور را متوقف میکنیم. حال در یک پروژه از نوع Console App، سرویس مورد نظر را اضافه کرده و متد Wait آن را فراخوانی میکنیم. به صورت زیر:
همان طور که میبینید قبل از فراخوانی متد Wait زمان جاری سیستم را نمایش داده و سپس بعد از فراخوانی دوباره زمان مورد را نمایش میدهیم. در مرحله اول با خطای زیر مواجه خواهیم شد:
دلیل اینکه Timeout Exception پرتاب شد این است که به صورت پیش فرض مقدار خاصیت sendTimeout برابر 59 ثانیه است، در نتیجه قبل از اینکه پاسخی از سمت سرور به کلاینت برگشت داه شود این Exception رخ میدهد. برای حل این مشکل کافیست در فایل app.config کلاینت در قسمت تنظیمات Binding ، تغییر زیر را اعمال کنیم:
حال خروجی به صورت زیر است:
مشخص است که تا زمانی که عملیات سمت سرور به پایان نرسد،(یا توجه به اینکه خروجی متد سمت سرور void است) اجرای برنامه در کلاینت نیز متوقف خواهد بود(اختلاف زمانهای بالا کمی بیش از یک دقیقه است).
در این مواقع زمانی که باید متدی سمت سرور فراخوانی شود و قرار نیست که خروجی نیز در اختیار کلاینت قرار دهد بهتر است که از متدهای یک طرفه استفاده نماییم. متدهای یک طرفه یا یه اصطلاح OneWay، هیچ پاسخی را به کلاینت برگشت نمیدهند و بلافاصله بعد از فراخوانی، کنترل اجرای برنامه را در اختیار کلاینت قرار خواهند داد. برای تعریف یک متد به صورت یک طرفه کافیست به صورت زیر عمل نماییم(مقدار خاصیت IsOneWay را در OperationContractAttribute برابر true خواهیم کرد):
حال اگر سرویس سمت کلاینت را به روز کرده و برنامه را اجرا کنیم خروجی به صورت زیر تغییر میکند:
پروژه ای از نوع Wcf Service App میسازیم و یک سرویس با یک متد که خروجی آن نیز void است خواهیم داشت. به صورت زیر:
[ServiceContract] public interface ISampleService { [OperationContract] void Wait(); }
public class SampleService : ISampleService { public void Wait() { Thread.Sleep( new TimeSpan( 0, 1, 0 ) ); } }
class Program { static void Main( string[] args ) { SampleService.SampleServiceClient client = new SampleService.SampleServiceClient(); Console.WriteLine( DateTime.Now ); client.Wait(); Console.WriteLine( DateTime.Now ); Console.ReadKey(); } }
دلیل اینکه Timeout Exception پرتاب شد این است که به صورت پیش فرض مقدار خاصیت sendTimeout برابر 59 ثانیه است، در نتیجه قبل از اینکه پاسخی از سمت سرور به کلاینت برگشت داه شود این Exception رخ میدهد. برای حل این مشکل کافیست در فایل app.config کلاینت در قسمت تنظیمات Binding ، تغییر زیر را اعمال کنیم:
<basicHttpBinding> <binding name="BasicHttpBinding_ISampleService" sendTimeout="0:2:0"/> </basicHttpBinding>
مشخص است که تا زمانی که عملیات سمت سرور به پایان نرسد،(یا توجه به اینکه خروجی متد سمت سرور void است) اجرای برنامه در کلاینت نیز متوقف خواهد بود(اختلاف زمانهای بالا کمی بیش از یک دقیقه است).
در این مواقع زمانی که باید متدی سمت سرور فراخوانی شود و قرار نیست که خروجی نیز در اختیار کلاینت قرار دهد بهتر است که از متدهای یک طرفه استفاده نماییم. متدهای یک طرفه یا یه اصطلاح OneWay، هیچ پاسخی را به کلاینت برگشت نمیدهند و بلافاصله بعد از فراخوانی، کنترل اجرای برنامه را در اختیار کلاینت قرار خواهند داد. برای تعریف یک متد به صورت یک طرفه کافیست به صورت زیر عمل نماییم(مقدار خاصیت IsOneWay را در OperationContractAttribute برابر true خواهیم کرد):
[ServiceContract] public interface ISampleService { [OperationContract( IsOneWay = true )] void Wait(); }
میبینید که اختلاف زمانهای بالا در حد چند ثانیه است که آن هم صرفا جهت فراخوانی متد سمت سرور بوده است. نکته مهم قابل ذکر این است که سرویس دهنده زمانی که با درخواستی جهت اجرای متد یک طرفه روبرو میشود، از آن جا که اجباری برای اجرای متد در همان زمان نیست در نتیجه این درخواستها در بافر ذخیره میشوند و سپس در زمان مناسب اجرا خواهند شد. اگر بافر برای ذخیره اجرای متدهای یک طرفه پر باشد در این حالت کلاینت برای فراخوانی متدهای یک طرفه بعدی باید منتظر خالی شدن بافر سمت سرور بماند.