WCF (Windows Communication Foundation) for Beginner – part 3

30 בדצמבר 2010

תגיות: ,
7 תגובות



 


ללמוד WCF פרק 3 – לתקשר עם Service שבאויר.

 

דוגמת הקוד של הפרק – להורדה

 

 

רשימת נושאים בפרק 3:


סיכום דוגמת קוד מהפרק הקודם.

מה Client צריך לעשות כדי לתקשר עם ה – Service.

יצירת Client ראשון בעזרת ChannelFactory.

יצירת Client שני בעזרת Service Reference.

 

 


סיכום דוגמת קוד מהפרק הקודם


בפרק הקודם למדנו מה צריך לעשות כדי להרים Service לאוויר,

ראשית: לכתוב את ה – Contract (בסך הכול Interface עם Attribute של ServiceContract)

שנית: לממש אותו (בסך הכול מחלקה רגילה המממשת Interface)

שלישית: להחליט מי ה – Host שלנו (בדוגמא מהפרק הקודם הלכנו על Console Application), להגדיר בקובץ הקונפיג את ההגדרות המתאימות (באיזה פרוטוקול, את מה חושפים וכו'), ולהשתמש במחלקה ServiceHost כדי להרים את השירות לאוויר.

 

כל הקוד ביחד נראה כך:

Contract:

 



namespace Contarcts


{


    [ServiceContract]


    public interface ICalc


    {


        [OperationContract]


        int Add(int a, int b);


 


        [OperationContract]


        int Sub(int a, int b);


    }


}



Service:

 



namespace Service


{


    public class Calc : ICalc


    {


        public int Add(int a, int b)


        {


            return a + b;


        }


 


        public int Sub(int a, int b)


        {


            return a – b;


        }


    }


}


 


 


Host – Config:

 



  <system.serviceModel>


    <services>


      <service name="Service.Calc" >


        <endpoint address="http://localhost:8412/MyCalcService"


                  binding="basicHttpBinding"


                  contract="Contarcts.ICalc"></endpoint>


      </service>


    </services>


  </system.serviceModel>


 


Host – Code:

 



namespace Host


{


    class Program


    {


        static void Main(string[] args)


        {


            ServiceHost calcHost = new ServiceHost(typeof(Calc));


            calcHost.Open();


 


            Console.ReadLine();


        }


    }


}


 


 


כשהקשרים בינייהם נראים כך:

יש לנו שלושה פרוייקטים, Contract, Service, Host

Contract לא מכיר אף אחד ויש לו Reference ל – System.ServiceModel

Service מכיר את Contract

Host מכיר את שניהם  ויש לו Reference ל – System.ServiceModel

 

אחרי שהחלק הזה קיים, ניתן להריץ את ה – host והוא מחכה לפניות, ברגע שהוא יקבל פניה שמתאימה לאחת מהמתודות שנחשפו דרך ה – Contract הוא יפעיל אותם.

 

כעת נגש לצד הלקוח.

 

 


מה Client צריך לעשות כדי לתקשר עם ה – Service


כדי שלקוח יוכל לפנות לשירות הוא צריך להכיר את ההגדרות של ה – Endpoint שה – Service נחשף דרכו, הוא צריך לדעת באיזה כתובת כמובן ה – Service מאזין ובאיזה פרוטוקולים הוא מוכן לקבל בקשות וכמובן עליו לדעת מה ה – Contract כלומר אילו מתודות אפשר להפעיל.

 

יצירת Client ראשון בעזרת ChannelFactory


למעשה יש שתי דרכים להגדיר את הלקוח כדי שהוא יוכל לעבוד עם השירות המרוחק, אחת אוטומטית ואחת ידנית, נתחיל עם הידנית:

הלקוח יכול לתקשר עם השירות בעזרת מחלקה מיוחדת הנקראת ChannelFactory, אנחנו נשתמש בה במידה ויש לנו Reference ישיר לפרוייקט ה – Contract (וזה אחת הסיבות שמומלץ להפריד בין הפרוייקטים של ה – Service לבין ה – Contract – מכיון שרק כך הלקוח יכול להחזיק Reference ל – Contract).

 

נייצר פרוייקט חדש מסוג Console Application ונקרא לו בשם ClientWithChannelFactory.

נוסיף לו Reference לפרוייקט של ה – Contract.

ונכתוב בקונפיג קוד מאוד דומה למה שכתבנו בפרוייקט של ה – Host

 




  <system.serviceModel>


    <client>


      <endpoint name="calcEndpoint"


              address="http://localhost:8412/MyCalcService"


              binding="basicHttpBinding"


              contract="Contarcts.ICalc"></endpoint>


    </client>


  </system.serviceModel>


 



אפשר לראות שה – Endpoint מוגדר באותה צורה שבה ה – Host הגדיר, ההבדל היחיד הוא שכאן ה – Endpoint עטוף באלמנט client וב – Host הוא היה עטוף באלמנט service.

בנוסף כאן ה – Endpoint קבל ערך למאפיין name – מיד נבין למה.

 

כעת נכתוב את הקוד הבא

 



namespace Client


{


    class Program


    {


        static void Main(string[] args)


        {


            ChannelFactory<ICalc> channel = new ChannelFactory<ICalc>("calcEndpoint");


            ICalc proxy = channel.CreateChannel();


 


            int res = proxy.Add(2, 4);


 


            channel.Close();


        }


    }


}


 


נשתמש במחלקה ChannelFactory כדי לייצר מופע שמתייחס ל – ICalc, בבנאי שלו הוא מקבל את השם של ה – Endpoint, לאחר מכן נשתמש במתודה CreateChannel כדי לקבל מופע של ICalc.

ונוכל להתחיל להשתמש במתודות – כמובן שה – Host חייב להיות באויר בזמן שמבצעים את השורות האלו.

 

 

יצירת Client שני בעזרת Service Reference


הרבה פעמים אין לנו Reference ישיר מהפרוייקט של ה – Client ל – Contract (או שאנחנו מתעצלים לכתוב לבד) ואנחנו רוצים שזה יקרה בצורה אוטומטית.

 

אפשר להשתמש בשירות של Visual Studio שנקרא Service Reference כדי לקבל את ה – Proxy, כדי לעשות זאת ה – Host שלנו חייב לחשוף את ה – wsdl (מסמך xml המתאר את השירות), נחזור לפרוייקט של ה – Host ונוסיף בקונפיג את הקוד הבא (מיד אחרי שהאלמנט services נסגר)

 



<behaviors>


  <serviceBehaviors>


    <behavior>


      <serviceMetadata httpGetEnabled="true"


                      httpGetUrl="http://localhost:8412/MyCalcService/Help"/>


    </behavior>


  </serviceBehaviors>


</behaviors>


 


בפרק הבא אני אסביר על המושג behaviors – כרגע כל מה שאני אגיד שמדובר בהגדרות שונות על השירות שאנחנו חושפים.

 

כעת נוסיף פרוייקט חדש מסוג Console Application ונקרא לו ClientWithServiceReference

בשלב הזה אנחנו חייבים להריץ את ה – Host (כדי ש – Visual Studio יוכל לקבל את קובץ ה – wsdl)

 

נלחץ קליק ימין על Add Reference בפרוייקט החדש ונבחר ב – Add Service Reference.

בתיבת הטקסט נוסיף את ה – url הבא – http://localhost:8412/MyCalcService/Help (הוא אותו כתובת שחשפנו במאפיין httpGetUrl)

נלחץ על GO ולאחר שהוא הוא ימצא את השירות, נכתוב בתיבת הטקסט (למטה) את השם CalcProxy.

 

Add Service Reference

 

 


כשנלחץ OK – הוא יצור עבורנו Proxy וכעת נוכל לכתוב את הקוד הבא:

 



namespace ClientWithServiceReference


{


    class Program


    {


        static void Main(string[] args)


        {


            CalcClient proxy = new CalcClient();


            int res = proxy.Add(2, 4);


        }


    }


}


 


אפשר לראות שהוא יצר לנו מאחורי הקלעים מחלקה עם אותו שם של ה – Service והוסיף את הסיומת Client.

בנוסף הוא גם ייצר לנו את קובץ הקונפיג, רק שהוא מוסיף כל מיני אלמנטים שלא צריך אותם אלא אם כן אנחנו רוצים לשנות את הערכים שלהם.

 

מה שהוא ייצר בקונפיג נראה ככה:

 



<system.serviceModel>


    <bindings>


        <basicHttpBinding>


            <binding name="BasicHttpBinding_ICalc" closeTimeout="00:01:00"


                openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"


                allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"


                maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"


                messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"


                useDefaultWebProxy="true">


                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"


                    maxBytesPerRead="4096" maxNameTableCharCount="16384" />


                <security mode="None">


                    <transport clientCredentialType="None" proxyCredentialType="None"


                        realm="" />


                    <message clientCredentialType="UserName" algorithmSuite="Default" />


                </security>


            </binding>


        </basicHttpBinding>


    </bindings>


    <client>


        <endpoint address="http://localhost:8412/MyCalcService" binding="basicHttpBinding"


            bindingConfiguration="BasicHttpBinding_ICalc" contract="CalcProxy.ICalc"


            name="BasicHttpBinding_ICalc" />


    </client>


</system.serviceModel>


 


זה קצת מבהיל בפעם הראשונה שמסתכלים על זה – אבל אל דאגה – בהמשך הפרקים נלמד ונבין כל אלמנט, כרגע אפשר פשוט למחוק את כל החלק העליון (bindings) וגם למחוק מהחלק התחתון את המאפיין bindingConfiguration,

בסופו של דבר כדי שזה יעבוד הקונפיג יכול להיראות כך:

 



<system.serviceModel>


  <client>


    <endpoint address="http://localhost:8412/MyCalcService"


              binding="basicHttpBinding"


              contract="CalcProxy.ICalc"


              name="BasicHttpBinding_ICalc" />


  </client>


</system.serviceModel>



שזה די דומה למה שאנחנו עשינו.

 

 

 


בפרק הבא נכנס קצת יותר לעומק למושגים Binding ו – Behaviors

הוסף תגובה
facebook linkedin twitter email

להגיב על Shlomo לבטל

האימייל לא יוצג באתר. שדות החובה מסומנים *

7 תגובות

  1. שמואל 31 בדצמבר 2010 ב 12:23

    עושה קצת סדר בדברים מחכה להמשך.

    הגב
  2. jasper5 בינואר 2011 ב 10:13

    Hi Shlomo !!! Wassup ??
    Could you please please please write an article about connection managed .NET + WCF app to unmanaged application. I try it once to connect between them via named-pipes but stuck on WCF implementation on unmanaged side (the program which opens named pipe and listen to incoming connection from .NET app)

    תודה מראש !!!

    הגב
  3. Shlomo5 בינואר 2011 ב 11:31

    אני אכתוב דוגמה בשמחה, (בעוד כמה פרקים)

    הגב
  4. דניאל26 בפברואר 2011 ב 20:00

    3 בעיות עד פרק 3 את הראשונה פתרתי אשמח אם תוכל לסייע לגבי ה2 הנותרות

    1.אני משער שאתה לא עובד עם win 7 כי אי אפשר להריץ את הקוד שלך המארח לא עולה בגלל שגיאה כזו :

    ל- HTTP לא היתה אפשרות לרשום את כתובת ה- URL‏ http://+:8888/MyCalcService/. לתהליך אין זכויות גישה אל מרחב שמות זה (ראה go.microsoft.com/fwlink לקבלת פרטים).

    זה נובע מהגנת ה UAC על מע' הפעלה כגון VISTA WIN7

    ןלכן הפתרון הוא להוסיף manifest לפרויקט שמאפשר חלון אישור בקרת חשבון משתמש (כן או לא)

    2.עם הFactory Channel התרגיל עבד מצויין כששני הפרויקטים client, host ישבו באותו מחשב אבל כששמתי את המארח במחשב אחד ואת הלקוח במחשב שני נוצרה בעיה שקיבלתי היום שלא מצאתי לה פתרון שגיאה מספר 10061 :

    TCP error code 10061: No connection could be made because the target machine actively refused it בניסיון לפתור את זה ביטלתי את חומת האש במחשב המארח והוספתי credentials אצל הלקוח הנה כך :

    System.Net.NetworkCredential c = new System.Net.NetworkCredential("pcname", "password channel.Credentials.Windows.ClientCredential = c;

    Contracts.ICalc proxy = channel.CreateChannel();

    בנוסף ב ADRESS של ה EndPoint כבר עוד לפני השגיאה שמתי את שם המחשב שלי , כדי לבדוק שאכן הוא מגיע למארח שיניתי בכוונה את הכתובת ושגיאה לגבי נקודת קצה שגויה התקבלה מה שאומר שאכן ניסיתי להגיע למארח הנכון

    3.בניסיון לעבוד עם add service reference אחרי הרמת השרת והוספת ה behavior בדיוק לפי ההנחיות שלך מתקבלת השגיאה הבאה:

    אירעה שגיאה בהורדת 'localhost/…/Help'.

    ‏‏הבקשה נכשלה עם מצב HTTP‏ 400:‏ Bad Request.

    ‏‏מטה-נתונים מכילים הפניה שאין אפשרות לפענח: 'localhost/…/Help'.

    ‏‏אין תמיכה בסוג התוכן application/soap+xml; charset=utf-8 בשירות localhost/…/Help. ייתכן שהאיגודים של הלקוח ושל השרת אינם תואמים.

    השרת המרוחק החזיר שגיאה: (415) Cannot process the message because the content type 'application/soap+xml; charset=utf-8' was not the expected type 'text/xml; charset=utf-8'..

    If the service is defined in the current solution, try building the solution and adding the service reference again

    הכתובת שהקלדתי (HTTP עם פורט משלי 8888) נכונה כי כשבכוונה אני משנה משהו השגיאה אומרת שאין נקודת קצה תואמת יש פה איזה בעיה עם UTF-8 מה העניין עם זה?

    אשמח לכל עזרה בתודה מראש

    דניאל

    הגב
  5. דוד2 במאי 2011 ב 10:44

    איפה הפרק הבא?

    הגב
  6. ולד10 בספטמבר 2011 ב 18:31

    לשאלתו של דניאל, ניתן לפתור את בעיה 3 כך:

    א. יש להוסיף את ה-attribute "שם" ל-behavior. למשל SimpleBehavior:

    ב. בתוך טאג ה-services יש להגדיר attribute נוסף בשם behaviorConfiguration המגדיר
    שאנו משתמשים ב-behavior שהוספנו, כך:

    הגב