WCF چیست؟ قسمت هفتم - ایجاد سرویس Restful

فایلهای مرتبط

ایجاد سرویس Restful

شاید بتوان گفت که سرویس های Rest جایگزین وب سرویس ها شده باشند، همانطور که می دانیم این نوع سرویس از پروتوکل HTTP پشتیبانی می کند و در پروژه های وب شاید مناسبترین انتخاب باشد.  ارسال و دریافت اطلاعات توسط سرویس های Rest در قالب xml و یا Json اتفاق می افتد که ساختار شناخته شده ای برای برنامه نویسان هستند.کار کردن با سرویس های REST بسیار ساده تر از کار کردن با وب سرویس های پیچیده ای مانند SOAP می باشد. 
حال برای تبدیل پروژه ایجاد شده ما به سرویس Rest چه باید بکنیم.
ابتدا باید تغییراتی در اینترفیس مربوط به سرویس خود ایجاد کنیم ( کلیه این تغییرات از یک استاندارد پیروی می کنند که ما هم طبق آن اسلوب باید تغییرات خود را روی سرویس و میزبان آن ایجاد کنیم. ابتدا به سراغ اینترفیس سرویس خود می رویم ، همانجا که Service Contract و Operation Contract  را نعریف کرده ایم. سرویس های Rest از چهار متد اصلی مورد نیاز برنامه نویسان پشتیبانی می کنند، و ما باید به هر کدام از متد های داخل Interface بگوییم که این متد قرار هست چه کاری برای ما انجام دهد. در کل از چهار دستور زیر برای تعریف متد های سرویس RESTful استفاده می کنیم :
GET برای بازیابی یک شی
POST برای ویرایش یک شی
PUT برای ایجاد یک شی
DELETE برای حذف یک شی

البته ما در مثال های خود در این مقاله از متد POST برای درچ و از PUT برای ویرایش استفاده کرده ایم.
با هر بار فراخوانی سرویس ما  ،باید یکی از این متد ها به سرور ارسال شود تا سرور بداند چه عملیاتی را باید انجام دهد.
اولین متد ما در  اینترفیس ما متد Add بود که دو پارامتر را از ما گرفته و جمع آن را به ما برمیگرداند. ابتدا باید مشخص کنیم که متد ما قرار است کدام یک از دستور های GET , POST ، PUT و یا DELETE را انچام دهد، برای این کار کافیست که در ابتای تعریف متد عبارت زیر را قرار دهیم:
[WebGet(UriTemplate = "add/{n1}/{n2}")]
[OperationContract]
double Add(double n1, double n2);
برای فعال شدن این امکانات و جلوگیری از خطای کامپایل ابتدا باید یک Namespace جدید به Reference های پروژه خود اضافه کنیم.   از کتابخانه دات نت System.ServiceModel.Web را به Reference های پروژه اضافه می کنیم و در ابتدای اینترفیس حود آن را  به اصطلاح خودمان Use می کنیم:
using System.ServiceModel.Web;
چون انتظار داریم متد Add از دستور های Getاستفاده کند از کلید WebGet استفاده کرده ایم ، همانطور که می بینید از کلمه add برای تعریف شناسه برای این متد استفاده کرده ایم که می نوانست هر عبارت دیگری نیز باشد و بعد از آن دو تا پارامتر به  URL  اضافه می کنیم. در زمان فراخوانی سرویس، این رشته به انتهای آدرس اولیه سرویس اضافه خواهد شد. مثلا بدین شکل:
http://localhost:8000/GettingStarted/CalculatorService/add/3/4
و به همین صورت هم فراخوانی خواهد شد. همین کار را برای سه متد بعدی انجام می دهیم. و نتیجه چنین خواهد شد:
namespace GettingStartedLib
{
    [ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
    public interface ICalculator
    {
        [WebGet(UriTemplate = "add/{n1}/{n2}")]
        [OperationContract]
        double Add(double n1, double n2);

        [WebGet(UriTemplate = "subtract/{n1}/{n2}")]
        [OperationContract]
        double Subtract(double n1, double n2);

        [WebGet(UriTemplate = "multiply/{n1}/{n2}")]
        [OperationContract]
        double Multiply(double n1, double n2);

        [WebGet(UriTemplate = "devide/{n1}/{n2}")]
        [OperationContract]
        double Divide(double n1, double n2);
    }
}
حال باید در پروژه  GettingStartedHost در کد مشخص کنیم که چه نوع سرویس را برای ما هاست کند. بنا براین به جای ایجاد یک سرویس  از نوع ServiceHost در مرحله دوم، یک سرویس از نوع  WebServiceHost ایجاد می کنیم:. کتابخانه System.ServiceModel.Web در اینجا هم باید Use شود.
مرحله سوم نیز بدین ترتیب باید تغییر پیدا کند:
به جای خط کد زیر:
// Step 3 Add a service endpoint.
selfHost.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "CalculatorService");

از خط کد زیر استفاده می کنیم:
// Step 3 Add a service endpoint.
selfHost.AddServiceEndpoint(typeof(ICalculator), new WebHttpBinding(), "CalculatorService").Behaviors.Add(new WebHttpBehavior());

همانطور که می بینید به جای نوع اتصال WSHttpBinding  از نوع اتصال  WebHttpBinding استفاده کرده ایم.
و همچنین یک WebHttpBehavoir  هم به آن اضافه کردیم.
اگر بخواهیم میزبان سرویس را اجرا کنیم خطای زیر را دریافت خواهیم کرد:
البته باید خط کد اولیه زیر را به صورت کامنت در آورده یا حذف کنیم:
// Step 3 Add a service endpoint.
// selfHost.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "CalculatorService");


InvalidOperationException

همانطور که مشاهده می کنید، خطایی که رخ داده است به خاطر وجود نوع پارامتر double است که برای URITemplate تخصیص داده ایم، در صورتی که از روش ارسال پارامتر به حالت /{n1}/{n2}/{n3}/  بخواهیم استفاده نماییم باید از نوع string تعریف کرده باشیم. ولی اگر پارامتر های مرتبط با URTemplate را به روش زیر تعریف کنیم، دیگر نیازی به تغییر نوع پارامتر نیست:
/?n1={n1}&n2={n2}
برای این که بتوانیم هر دو حالت را تست کنیم، پارامتر های ورودی متد اول و دوم را به روش اول (/{n1}/{n2}/{n3}/) و متدهای سوم  و چهارم را به روش دوم (/?n1={n1}&n2={n2}) تعریف می کنیم. بنابراین در دو متد اول باید نغییراتی را اعمال کنیم. و نوع پارامتر های ورودی را از double به string تغییر دهیم. بنابراین اینترفیس ما به شکل زیر تغییر خواهد کرد:
public interface ICalculator
{
    [WebGet(UriTemplate = "add/{n1}/{n2}")]
    [OperationContract]
    double Add(string n1, string n2);

    [WebGet(UriTemplate = "subtract/{n1}/{n2}")]
    [OperationContract]
    double Subtract(string n1, string n2);

    [WebGet(UriTemplate = "multiply/?n1={n1}&n2={n2}")]
    [OperationContract]
    double Multiply(double n1, double n2);

    [WebGet(UriTemplate = "devide/?n1={n1}&n2={n2}")]
    [OperationContract]
    double Divide(double n1, double n2);
}

و کلاس ما نیز به شکل زیر تغییرات خواهد داشت:
public class CalculatorService : ICalculator
{
    public double Add(string n1, string n2)
    {
        double result = Convert.ToDouble(n1) + Convert.ToDouble(n2);
        Console.WriteLine("Received Add({0},{1})", n1, n2);
        // Code added to write output to the console window.
        Console.WriteLine("Return: {0}", result);
        return result;
    }

    public double Subtract(string n1, string n2)
    {
        double result = Convert.ToDouble(n1) - Convert.ToDouble(n2);
        Console.WriteLine("Received Subtract({0},{1})", n1, n2);
        Console.WriteLine("Return: {0}", result);
        return result;
    }

    public double Multiply(double n1, double n2)
    {
        double result = n1 * n2;
        Console.WriteLine("Received Multiply({0},{1})", n1, n2);
        Console.WriteLine("Return: {0}", result);
        return result;
    }

    public double Divide(double n1, double n2)
    {
        double result = n1 / n2;
        Console.WriteLine("Received Divide({0},{1})", n1, n2);
        Console.WriteLine("Return: {0}", result);
        return result;
    }
}

در پروژه  GettingStartedHost چند خط کد زیر را هم اضافه می کنیم تا  نام سرویس و endpoint مربوطه را به ما نمایش دهد. بنابراین مرحله 5 از کد مربوطه به شکل زیر خواهد بود:
// Step 5 Start the service.
selfHost.Open();
Console.WriteLine("The service is ready.");
Console.WriteLine("{0} is up and running with these endpoints: ", selfHost.Description.ServiceType);
foreach (var se in selfHost.Description.Endpoints)
{
    Console.WriteLine(se.Address);
}
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();

حال پروژه GettingStartedHost را اجرا می کنیم تا سرویس ما توسط این برنامه کنسول میزبانی گردد و ما بتوانیم آن را تست کنیم.  بعد ار اجرای پروژه صفحه زیر نمایان خواهد شد:

ServiceIsReady

حال سرویس Rest ما مهیای تست است. برای تست باید مرور گر خود را اجرا کرده و URL هایی درستی را که سرویس ما را فراخوانی می کنند را توسط مرورگر صدا بزنیم. با توجه به تعریفی که برای چهار متد داخل سرویس داشته ایم URL های مربوطه چنین خواهد بود:
برای تست متد add از url زیر استفاده می کنیم:
http://localhost:8000/GettingStarted/CalculatorService/add/3/4

آن را در بخش آدرس مرورگر وارد کرده و کلید Enter را فشار میدهیم تا اجرا شود. نتیجه زیر را مشاهده خواهیم کرد:

AddMethodResult

برای متد Subtract از URL زیر استفاده می کنیم:
http://localhost:8000/GettingStarted/CalculatorService/subtract/8/2
آن را در بخش آدرس مرورگر وارد کرده و کلید Enter را فشار میدهیم تا اجرا شود. نتیجه زیر را مشاهده خواهیم کرد:

SubtractMethodResult

اگر بخواهیم دو متد Multuply و Devide را به همین روش فراخوانی کنیم، پیام خطایی دریافت خواهیم کرد که در زیر میبینیم:

MulitplyError

بنابراین نحوه فراخوانی دو متد بعدی باید منطبق با نحوه تعریف پارامتر های ورودی آن باشد.
پس متد اول را به روش زیر فراخوانی می کنیم و نتیجه را نیز در زیر آن مشاهده می کنیم:

http://localhost:8000/GettingStarted/CalculatorService/multiply/?n1=17&n2=23

MultiplyMethodResult.jpg

متد دوم را نیز فراخوانی می کنیم و نتیجه را هم مشاهده می کنیم:

http://localhost:8000/GettingStarted/CalculatorService/divide/?n1=170&n2=21

DevideMethodResult.jpg

اگر صفحه CMD اجرا کننده میزبان سرویس را مشاهده کنید، کلیه عملیاتی را که توسط مرورگر فراخوانی کردیم آنجا نیز اجرا شده است.

WCFExecutionResult

توابعی را که مشاهده کردید همه از  متد GET از سرویس Rest استفاده می کرد که در اصل برای بازیابی اطلاعات از آنها استفاده می کنیم. حال می خواهیم برای دو متد POST و DELETE  نیز تابعی را نوشته و از آن استفاده کنیم. برای فراخوانی متد POST و DELETE از یک فایل واسط به نام  httputil.js استفاده خواهیم کرد تا بتوانیم پارامتر های ورودی مورد نیاز تابع مورد نظر را به آن ارسال کنیم. به عنوان مثال اگر ما بخواهیم یک لیست از اعداد را به تابع Insert ارسال کنیم باید از این فایل استفاده کرده و یک لیست از اعداد را در قالب XML به آن ارسال کنیم. البته ما از این فایل واسط برای این استفاده می کنیم که صحت کارکرد سرویس خود را تست کنیم. در دنیای واقعی برنامه نوسی سمت سرویس گیرنده، نحوه استفاده از سرویس ها کمی متفاوت تر خواهد بود.
ما  سه متد زیر را به Interface خود اضافه می کنیم:

[WebInvoke(Method = "POST", UriTemplate = "insert")]
[OperationContract]
List<int> InsertList(List<int> numbers);

[WebGet(UriTemplate = "show")]
[OperationContract]
List<int> ShowList();

[WebInvoke(Method = "DELETE", UriTemplate = "delete/{number}")]
[OperationContract]
List<int> DeleteItem(string number);

[WebInvoke(Method = "PUT", UriTemplate = "edit/{n1}/{n2}")]
[OperationContract]
List<int> UpdateItem(string n1, string n2);

متد اول برای ارسال کردن یک لیست به تابع  و وارد کردن آن در یک فضای ذخیره کننده این مقادیر استفاده خواهد شد. البته چون در مثال ما فضای فیزیکی مانند فایل یا بانک اطلاعاتی برای ذخیره کردن این دیتا و وارد کردن این اعداد به بانک اطلاعاتی وجود ندارد، لذا آنها را در یک لیست (List<int>) از اعداد که در ابتدای کد تعریف خواهیم کرد نگهداری می کنیم.
متد دوم نیز برای نمایش اعدادی که توسط تابع قبل در لیست ذخیره کردیم پیاده سازی می شود و متد سوم نیز برای حذف یک عدد از این   لیست پیاده سازی خواهد شد. بدنه سه متد فوق به شکل زیر خواهد بود. لطفا به نحوه تعریف متد های POST و DELETE و عبارات استفاده شده در سطر های مربوطه دقت کنید. همانطور که می بینید دیگر از عبارت WebGet خبری نیست و از WebInvoke استفاده شده است که  در این صورت حتما باید غیر از UriTemplate  متد POST یا DELETE را هم در آن قرار دهیم تا سرویس بداند چه رفتاری قرار هست نشان دهد. ( البته این یک استاندارد در تعریف متدها  و توابع داخل سرویس های REST است).
بدنه متد های پیاده سازی شده در داخل کلاس سرویس ما بدین شکل خواهد بود.

public List<int> InsertList(List<int> numbers)
{
    for (int i = 0; i < numbers.Count; i++)
    {
        NumberList.Add(numbers[i]);
        Console.WriteLine("Number is ({0})", numbers[i]);
    }
    return numbers;
}

public List<int> ShowList()
    {
    for (int i = 0; i < NumberList.Count; i++)
    {
        Console.WriteLine("Number is ({0})", NumberList[i]);
    }
    return NumberList;
}

public List<int> DeleteItem(string number)
{
    for (int i = 0; i < NumberList.Count; i++)
    {
        if (NumberList[i] == Convert.ToInt32(number))
        {
            NumberList.RemoveAt(i);
        }
        Console.WriteLine("Deleted Number is ({0})", NumberList[i]);
    }
    return NumberList;
}

public List<int> UpdateItem(string n1, string n2)
{
    for (int i = 0; i < NumberList.Count; i++)
    {
        if (NumberList[i] == Convert.ToInt32(n1))
        {
            NumberList[i] = Convert.ToInt32(n2);
        }
        Console.WriteLine("Number changed from ({0}) to ({1})", n1, NumberList[i]);
    }
    return NumberList;
}

NumberList را هم به صورت  static در بالای کلاس خود تعریف می کنیم تا بتوانیم در طول اجرای برنامه از مقادیر داخل آن در توابع خود استفاده کنیم. بدین شکل:

private static List<int> NumberList = new List<int>();

حال متد های ما آماده اند تا از آنها استفاده کنیم.  برای تست متد های POST،DELETE , PUT نیاز به ابزاری داریم که دیتای ما را به متد های نوشته شده پاس کند. یک ابزار به نام  httputil.js وجود دارد که ما از آن برای تست صحت کارکرد متد های خود استفاده خواهیم کرد، می توانید با جستجوی ساده در اینترنت به این ابزار دسترسی پیدا کنید.
برای تست متد اول به نام  InsertList نیاز داریم ما یک لیست از اعداد به آن ارسال کنیم، برای این کار باید یک فایل XML به آن ارسال کنیم که شامل اعداد مورد نظر ما باشند. ما اگر یک متدی بنویسیم که اعداد زوح بین 20 و 100 را به عنوان یک لیست برای ما ارسال کند، یعنی خروجی تابع اشاره شده لیستی از این اعداد باشد ، و در مرورگر به روش های اشاره شده قبلی آن متد را فراخوانی کنیم، خروجی آن یک XML به شکل زیر خواهد بود:

<ArrayOfint xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <int>20</int>
    <int>22</int>
    <int>24</int>
    <int>26</int>
    <int>28</int>
    <int>30</int>
    <int>32</int>
    <int>34</int>
    <int>36</int>
    <int>38</int>
    <int>40</int>
    <int>42</int>
    <int>44</int>
    <int>46</int>
    <int>48</int>
    <int>50</int>
    <int>52</int>
    <int>54</int>
    <int>56</int>
    <int>58</int>
    <int>60</int>
    <int>62</int>
    <int>64</int>
    <int>66</int>
    <int>68</int>
    <int>70</int>
    <int>72</int>
    <int>74</int>
    <int>76</int>
    <int>78</int>
    <int>80</int>
    <int>82</int>
    <int>84</int>
    <int>86</int>
    <int>88</int>
    <int>90</int>
    <int>92</int>
    <int>94</int>
    <int>96</int>
    <int>98</int>
    <int>100</int>
</ArrayOfint>
ممی توانیم نتیجه بگیریم که اگر همین ساختار را درون یک فایل xml ذخیره کنیم و در صورت نیاز اعداد دلخواه خود را جایگزین اعداد جاری کنیم، می توانیم به عنوان پارامتر ورودی به تابع خود  ارسال نماییم.
ابتدا می خواهیم متد InsertList را فراخوانی نماییم. برای این کار به روش زیر عمل می کنیم.
ابتدا فایل httputil.js و فایل xml ار در یک پوشه کنار هم قرار می دهیم.
CMD را اجرا می کنیم و با اجرا و فراخوانی احکام مورد نیاز داخل فولدر مربوطه می رویم
کد زیر را اجرا می کنیم تا محتوای فایل XML ما به تابع مربوطه ارسال شده و آن تابع اجرا گردد.

httputil.js POST http://localhost:8000/GettingStarted/CalculatorService/insert evennumbers.xml
در اصل نحوه استفاده از فایل httputil.js به شکل زیر است:
Usage: httputil.js method uri file
که اگر مشاهده بکنید، مقدار مناسب هر عبارت جایگزین شده و سپس دستور مربوطه فراخوانی شده است.

بعد از اجرای دستور فوق پیام زیر ظاهر خواهد شد:

httputil-js-POST

بعد از اجرای این دستور اعداد زوج داخل این XML به متد  InsertList ارسال شده و این متد نیز آنها را داخل لیست  NumberList ذخیره می کند. برای اینکه مطمئن شویم، حال تابع و متد  ShowList را فراخوانی می کنیم تا محتوای لیست NumberList  را به ما نشان دهد.
عبارت زیر را در بخش آدرس مرورگر خود وارد کرده و کلید Enter را فشار می دهیم.
http://localhost:8000/GettingStarted/CalculatorService/show

نتیجه کار چنین خواهد بود:

ShowListMethod

حال متد  DeleteItem را تست می کنیم. برای تست این متد نیز عبارت زیر را در CMD فراخوانی می کنیم.

httputil.js DELETE http://localhost:8000/GettingStarted/CalculatorService/delete/20
این دستور عدد 20 را در صورت وجود داشتن در لیست  NumberList ، این عدد را از لیست حذف می نماید.
ابن دستور را برای چند عدد دیگر تکرار می کنیم.
httputil.js DELETE http://localhost:8000/GettingStarted/CalculatorService/delete/40
httputil.js DELETE http://localhost:8000/GettingStarted/CalculatorService/delete/52
httputil.js DELETE http://localhost:8000/GettingStarted/CalculatorService/delete/66
حال اگر  دستور زیر رو مجددا فراخوانی کنیم نتیجه زیر مشاهده خواهد شد:
http://localhost:8000/GettingStarted/CalculatorService/show

ShowListMethodAfterDelete

همانطور که مشاهده می کنید، اعداد 20و 40،52،66 از لیست ما حذف شده اند.


نتیجه کار چنین خواهد بود:

ShowListMethodAfterDelete  

حال متد  UpdateItem را تست می کنیم. برای تست این متد نیز عبارت زیر را در CMD فراخوانی می کنیم.

httputil.js PUT http://localhost:8000/GettingStarted/CalculatorService/edit/30/55555
این دستور عدد 30 را در صورت وجود داشتن در لیست  NumberList ، با عدد 555555 جایگزین می نماید.
ابن دستور را برای چند عدد دیگر تکرار می کنیم.
httputil.js PUT http://localhost:8000/GettingStarted/CalculatorService/edit/50/55555
httputil.js PUT http://localhost:8000/GettingStarted/CalculatorService/edit/60/55555 
httputil.js PUT http://localhost:8000/GettingStarted/CalculatorService/edit/70/55555 
حال اگر  دستور زیر رو مجددا فراخوانی کنیم نتیجه زیر مشاهده خواهد شد:
http://localhost:8000/GettingStarted/CalculatorService/show

PutMethodResult

بدین ترتیب نحوه تبدیل سرویس ما به یک سرویس Restful نشان داده شد.
ما در پروژه  GettingStartedSite نیز باید تغییراتی را اعمال کنیم تا بتوانیم از سرویس مربوطه  که در IIS میزبانی کرده ایم استفاده کنیم. ابتدا سراغ پروژه GettingStartedHost میرویم. برای اینکه کد قبلی را حفظ کنیم، داحل فایل اصلی پروژه به نام Program.cs یک متد به نام StartServiceHostProgrammatically ایجاد کرده و کد قبلی را داخل آن Paste می کنیم.

private static void StartServiceHostProgrammatically()
{
    // Step 1 Create a URI to serve as the base address.
    Uri baseAddress = new Uri("http://localhost:8000/GettingStarted/");

    // Step 2 Create a WebServiceHost instance
    WebServiceHost selfHost = new WebServiceHost(typeof(CalculatorService), baseAddress);

    try
    {

        // Step 3 Add a service endpoint.
        selfHost.AddServiceEndpoint(typeof(ICalculator), new WebHttpBinding(), "CalculatorService").Behaviors.Add(new WebHttpBehavior());

        // Step 4 Enable metadata exchange.
        ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
        smb.HttpGetEnabled = true;
        selfHost.Description.Behaviors.Add(smb);

        // Step 5 Start the service.
        selfHost.Open();
        Console.WriteLine("The service is ready.");
        Console.WriteLine("{0} is up and running with these endpoints: ", selfHost.Description.ServiceType);
        foreach (var se in selfHost.Description.Endpoints)
        {
            Console.WriteLine(se.Address);
        }
        Console.WriteLine("Press <ENTER> to terminate service.");
        Console.WriteLine();
        Console.ReadLine();

        // Close the ServiceHostBase to shutdown the service.
        selfHost.Close();
    }
    catch (CommunicationException ce)
    {
        Console.WriteLine("An exception occurred: {0}", ce.Message);
        selfHost.Abort();
    }
}

اگر به یاد داشته باشید کلیه تنظیمات مربوط به سرویس داخل کد تعریف می شد که الان داخل متد  StartServiceHostProgrammatically قرار دارد. حال می خواهیم بخشی از تنظیمات مربوطه را داخل  App.config قرار دهیم. کد فعلی داخل App.Config به شکل زیر است: 

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
    </startup>
</configuration>
 
همانطور که مشاهده می فرمایید هیچ کدی در رابطه با سرویس ما در این فایل وجود ندارد . حال تنظیمات زیر را به این فایل اضافه می کنیم ( نحوه تعریف استانداردی دارد که باید رعایت گردد):

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
    </startup>
    <system.serviceModel>
        <services>
            <service name="GettingStartedLib.CalculatorService">
                <endpoint address="
http://localhost:8000/GettingStarted/CalculatorService"
                binding="webHttpBinding" bindingConfiguration="" contract="GettingStartedLib.ICalculator" />
            </service>
        </services>
    </system.serviceModel>

</configuration>
 
از المان های داخل این تنظیمات کاملا معلوم است که به چه هدفی قرار داده شده اند.
name برای قرار دادن نام سرویس همراه با nameSpace مربوطه است.
همانطور که می دانید endpoint برای مشخص کردن نحوه اتصال ماست که چند المان دارد:
address که آدرس و در اصل به نوعی URL است که توسط آن سرویس فراخوانی می شود.
binding نحوه و پروتکل اتصال ما را تعیین می کند که در سرویس های  webHttpBinding ، Restful است
Contract نیز به قرار داد ما اشاره دارد که در اصل آدرس اینترفیس ماست.
حال تنظیمات ما آماده است و App.config تکمیل شده است. این تنظیمات را به روش دیگری نیز می توانیم انجام دهیم که قبلا در مورد آن صحبت کرده ایم و آن استفاده از  ویزارد Edit WCF Configuration است.
تصاویر مرحله به مرحله آن را مشاهده می کنید، فراموش نشود بعد از اتمام کار باید تغییرات انجام یافته ذخیره گردد تا در App.Config اعمال گردند. فقط در انتها باید نوع binding را به webHttpBinding تغییر دهیم.

مرحله اول :

Edit-WCF-Configuration-01-ServiceType  

مرحله دوم:

Edit-WCF-Configuration-02-Contract  

مرحله سوم:

Edit-WCF-Configuration-03-protocol  

مرحله چهارم:

Edit-WCF-Configuration-04-Binding  

مرحله پنجم:

Edit-WCF-Configuration-05-Address  

مرحله ششم:

Edit-WCF-Configuration-06-Finish

حال کد دیگری را باید در پروژه  GettingStartedHost ، جایگزین کد قبلی کنیم، یعنی در اصل تغییر کوچکی در کد قبلی باید بدهیم. کد جدید را داخل یک متد قرار می دهیم و آن را در جای خود فراخوانی می کنیم. متد جدید با کمی تغییرات روی کد قبلی به شرح زیر  خواهد بود.

private static void StartServiceHost()
{
    // Step 1 Create a WebServiceHost instance
    WebServiceHost selfHost = new WebServiceHost(typeof(CalculatorService));

    try
    {
        // Step 2 Start the service.
        selfHost.Open();

        Console.WriteLine("The service is ready.");
        Console.WriteLine("{0} is up and running with these endpoints: ", selfHost.Description.ServiceType);
        foreach (var se in selfHost.Description.Endpoints)
        {
            Console.WriteLine(se.Address);
        }
        Console.WriteLine("Press <ENTER> to terminate service.");
        Console.WriteLine();
        Console.ReadLine();

        // Close the ServiceHostBase to shutdown the service.
        selfHost.Close();
    }
    catch (CommunicationException ce)
    {
        Console.WriteLine("An exception occurred: {0}", ce.Message);
        selfHost.Abort();
    }
}
همانطور که مشاهده می فرمایید از 5 مرحله تعریف و فعال سازی سرویس تنها دو مرحله آن را نیاز داریم تا بتوانیم سرویس خود را میزبانی کنیم. مراحلی را که از کد حذف کرده ایم به نحوی در داخل Web.Config  قرار داده شده اند.

ححال نوبت اعمال تغییرات در پروژه GettingStartedSite است که از طریق این پروژه سرویس خودر را روی IIS هاست کرده ایم. فایل  Web.config را باز کرده و  کلیه کد های مرتبط به سرویس را کامنت می کنیم، می خواهیم کاری کنیم نا همه این تنظیمات به  طور اتوماتیک اتفاق بی افتد. بعد از کامنت کردن کد های مرتبط با تعریف و تنظیمات سرویس کد زیر را خواهیم داشت:

<?xml version="1.0"?>
<configuration>

    <appSettings>
        <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
    </appSettings>
    <system.web>
        <compilation debug="false" targetFramework="4.5" />
        <httpRuntime targetFramework="4.5"/>
    </system.web>

    <!-- Deleted From Here -->
    <!--<system.serviceModel>
        <services>
            <service name="GettingStartedLib.CalculatorService">
                <endpoint address="basic" binding="basicHttpBinding" bindingConfiguration="" name="basicHttpBinding" contract="GettingStartedLib.ICalculator" />
            </service>
        </services>
        <behaviors>
            <serviceBehaviors>
                <behavior name="">
                    <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <protocolMapping>
            <add binding="basicHttpsBinding" scheme="https" />
        </protocolMapping>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
    </system.serviceModel>-->


    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true"/>
        <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
        -->
        <directoryBrowse enabled="true"/>
    </system.webServer>
</configuration>

کدی که به رنگ سبز نوشته شده است کدی است که میتواند حذف گردد. حال یک تغییر کوچک در فایل  Service.svc می دهیم .
اگر فایل Service.svc را باز کنیم کد زیر را مشاهده خواهیم کرد:

<%@ ServiceHost Language="C#" Debug="true" Service="GettingStartedLib.CalculatorService"%>
کد زیر زیر را به انتهای کد فوق اضافه می کنیم و تمام.

Factory="System.ServiceModel.Activation.WebServiceHostFactory"
پس کد انتهایی چنین خواهد بود:

<%@ ServiceHost Language="C#" Debug="true" Service="GettingStartedLib.CalculatorService" Factory="System.ServiceModel.Activation.WebServiceHostFactory"%>

ححال سرویس میزبانی شده ما روی IIS آماده استفاده است. برای تست آن ، مراحل زیر را مشابه با مراحلی که در بخش های قبلی انجام داده ایم ، انجام می دهیم.
ابتدا فایل  Service.svc را فراخوانی می کنیم تا url ما برای فراخوانی معلوم گردد. برای ان کار روی Service.svc داخل پروژه کلیک راست می کنیم و سپس  View In Browser  را کلیک می کنیم. صفحه ای روی مرورگر باز شده و عبارت زیر مشاهده می شود.

BrowseService.svc

url ما مشخص شد: http://localhost:5532/Service.svc
حال  url بالا را جایگزین url قبلی (http://localhost:8000/GettingStarted/CalculatorService) می کنیم. و url های زیر را در مرور گر صدا می کنیم تا نتایج را مشاهده کنیم:
1) http://localhost:5532/Service.svc/add/3/4  را صدا می زنیم  نتیجه زیر حاصل می شود:

 AddMethodResultWithSvc

2) http://localhost:5532/Service.svc/subtract/1/2 را  صدا می زنیم و نتیجه زیر حاصل می شود:

SubtractMethodResultWithSvc

3) http://localhost:5532/Service.svc/multiply/?n1=17&n2=23 را صدا می زنیم  و نتیجه زیر بدست می آید:
 
MultiplyMethodResultWithSvc

4) http://localhost:5532/Service.svc/divide/?n1=170&n2=21 را صدا می زنیم  و نتیجه زیر را خواهیم دید:

DevideMethodResultWithSvc

5) حال مثل روش قبلی می خواهیم از طریق httputil.js متد http://localhost:5532/Service.svc/insert را فراخوانی کنیم.  بعد از فراخوانی url مربوطه از طریق Command Prompt نتیجه زیر را خواهیم داد:

httputil-js-POST-WithSvc


6) حال اگر آدرس http://localhost:5532/Service.svc/show را فراخوانی کنیم نتیجه زیر را مشاهده خواهیم کرد:

ShowListMethodWithSvc

7) حال می خواهیم چند عدد را از این لیست حذف کنیم و متد Delete را فراخوانی کنیم.
متد های زیر را از طریق CMD فراخوانی و اجرا می کنیم:

httputil.js DELETE http://localhost:5532/Service.svc/delete/20
httputil.js DELETE http://localhost:5532/Service.svc/delete/40
httputil.js DELETE http://localhost:5532/Service.svc/delete/52
httputil.js DELETE http://localhost:5532/Service.svc/delete/66 

httputil-js-DELETE-WithSvc

حال اگر آدرس http://localhost:5532/Service.svc/show را دوباره فراخوانی کنیم نتیجه زیر را مشاهده خواهیم کرد:

ShowListMethodAfterDeleteWithSvc

8) حال می خواهیم چند عدد را در لیست  ویرایش کنیم و متد Update را فراخوانی کنیم.
متد های زیر را از طریق CMD فراخوانی و اجرا می کنیم:

httputil.js PUT http://localhost:5532/Service.svc/edit/30/55555
httputil.js PUT http://localhost:5532/Service.svc/edit/50/55555
httputil.js PUT http://localhost:5532/Service.svc/edit/60/55555
httputil.js PUT http://localhost:5532/Service.svc/edit/70/55555
حال اگر آدرس http://localhost:5532/Service.svc/show را دوباره فراخوانی کنیم نتیجه زیر را مشاهده خواهیم کرد:

ShowListMethodAfterUpdateWithSvc

همانطور که مشاهده فرمودید در ابتدای URL های ما عبارت  http://localhost:5532/Service.svc قرار داشت، این آدرسی هست که IIS Express در اختیار ما قرار می دهد. امکان این وجود دارد که عدد موجود در این URL در اجرا های بعدی  تغییر یابد. اگر به خاطر داشته باشید ما سرویس خود را در  IIS اصلی ویندوز نیز میزبانی کردیم و بنابراین ما می توانیم با جایگزین کردن آدرس فوق با آدرس  http://localhost/GettingStartedSite/Service.svc احتمال بروز این مشکل را به صفر برسانیم  و کلیه عملیات قبلی را با URL جدید انجام دهیم.
 


منابع:

WCF Tutorial
Developing Service-Oriented Applications with WCF



آخرین بروزرسانی
۱۶ اسفند ۱۴۰۲ 
تعداد کلیک
۴,۸۹۳

فهرست نظرها و ارسال نظر جدید

نام را وارد کنید
ایمیل را وارد کنید
تعداد کاراکتر باقیمانده: 1000
نظر خود را وارد کنید