Study on WCF-11: WCF client asynchronous call service, wcf-11
Preface:
- In the previous articleWCFPreliminary Study-10: WCFClient calls ServiceI have introduced in detail how the WCF client calls the service. However, these operations are performed synchronously. Sometimes we need to process the application for a long time and get the returned results, but do not want to affect the execution of the Code after the program. In this case, we need to consider using an Asynchronous Method to call the service. Note that the Asynchronous Method is completely for the client. It has nothing to do with the method of the WCF service contract, that is, without changing the operation contract, we can call the WCF Service synchronously or asynchronously.
WCFAsynchronous client service call method:
- Call the Service asynchronously through a proxy. The client can call this interface asynchronously by using the event-driven asynchronous call model. The event-based Asynchronous model design guidelines stipulate that if multiple values are returned, one value is returned as the Result attribute, and other values are returned as the attributes of the EventArgs object. One of the results is that, if the client uses the event-based Asynchronous Command Option to import metadata and multiple values are returned for this operation, the default EventArgs object returns a value as the Result attribute, the other returned values are the attributes of the EventArgs object. Use the/messageContract command to receive a message object as the Result property and use the returned value as the property of the object. This will generate a signature that will return the response message as the Result attribute on the EventArgs object. Then, all internal return values are the attributes of the Response Message object.
- Use the channel factory to call the operation asynchronously. Event-driven asynchronous call model is not supported when ChannelFactory <TChannel> is used. In this case, we need to asynchronously rewrite the service contract interface. Each method contains a set of beginXXX and endXXX, and XXX represents the method name. In addition, we need to set the AsyncPattern attribute on the Asynchronous Operation Method to true. Call the previous method, and then retrieve the result when the operation is complete.
WCFThe client asynchronously calls the service instance:
- Shows the project structure:
- Engineering Structure Description:
The IUserInfo. cs code is as follows:
Using System. ServiceModel; using System. Collections. Generic; using System. Runtime. Serialization; namespace Service {[ServiceContract] public interface IUserInfo {[OperationContract] User [] GetInfo (int? Id = null);} [DataContract] public class User {[DataMember] public int ID {get; set;} [DataMember] public string Name {get; set ;} [DataMember] public int Age {get; set;} [DataMember] public string Nationality {get; set ;}}}View Code
The code for UserInfo. cs is as follows:
Using System; using System. collections. generic; using System. linq; using System. text; using System. threading; namespace Service {public class UserInfo: IUserInfo {public User [] GetInfo (int? Id = null) {Thread. sleep (1000); List <User> Users = new List <User> (); Users. add (new User {ID = 1, Name = "JACK", Age = 20, Nationality = "CHINA"}); Users. add (new User {ID = 2, Name = "TOM", Age = 18, Nationality = "JAPAN"}); Users. add (new User {ID = 3, Name = "SMITH", Age = 22, Nationality = "KOREA"}); Users. add (new User {ID = 4, Name = "ALENCE", Age = 21, Nationality = "INDIA"}); Users. add ( New User {ID = 5, Name = "JOHN", Age = 22, Nationality = "SINGAPORE"}); if (id! = Null) {return Users. Where (x => x. ID = id). ToArray () ;}else {return Users. ToArray ();}}}}View Code
2. Host: console application. Add a reference to the Service assembly and Host the Service program.
The Program. cs code is as follows:
Using System; using System. collections. generic; using System. linq; using System. text; using Service; using System. serviceModel; namespace Host {class Program {static void Main (string [] args) {using (ServiceHost host = new ServiceHost (typeof (UserInfo) {host. opened + = delegate {Console. writeLine ("the service has been started. Press any key to terminate! ") ;}; Host. Open (); Console. Read ();}}}}View Code
The App. config code is as follows:
<? Xml version = "1.0"?> <Configuration> <system. serviceModel> <services> <service name = "Service. userInfo "behaviorConfiguration =" mexBehavior "> 3. Client1: console application. Add a reference to the service endpoint address http: // localhost: 1234/UserInfo/, set the service namespace to UserInfoServiceRef, click Advanced Settings, and select the generate Asynchronous Operation Option,
After the client proxy class and configuration file code are generated, the client 1 calls the service.
The Code of Program. cs is as follows:
Using System; using System. collections. generic; using System. linq; using System. text; using Client1.UserInfoServiceRef; namespace Client1 {class Program {static void Main (string [] args) {UserInfoClient proxy = new UserInfoClient (); proxy. getInfoCompleted + = new EventHandler <GetInfoCompletedEventArgs> (proxy_GetInfoCompleted); proxy. getInfoAsync (null); Console. writeLine ("this string is output before calling the method, indicating that the asynchronous call is successful! "); Console. read ();} static void proxy_GetInfoCompleted (object sender, GetInfoCompletedEventArgs e) {User [] Users = e. result. toArray (); Console. writeLine ("{0,-10} {1,-10} {2,-10} {3,-10}", "ID", "Name ", "Age", "Nationality"); for (int I = 0; I <Users. length; I ++) {Console. writeLine ("{0,-10} {1,-10} {2,-10} {3,-10}", Users [I]. ID. toString (), Users [I]. name. toString (), Users [I]. age. toString (), Users [I]. nationality. toString ());}}}}View Code
From the code above, we can see that the client proxy class calls adopt the event-driven mechanism. The service method GetInfo () is used together with the event-based Asynchronous call method and the form is GetInfoCompleted. The specific implementation of the client in the proxy_GetInfoCompleted event, through the parameter typeGetInfoCompletedEventArgsOfResult to obtain the returned Result. Proxy.GetInfoAsync(Null)The Code indicates that the service starts asynchronous calling. On this client, I specially outputConsole.WriteLine("This string is output before the method is called, indicating that the asynchronous call is successful!")A string of text to prove that the service is called asynchronously. Because in the operation contract GetInfo () method, I made the program thread sleep for 1 s to simulate the program execution time. If the client calls the service for asynchronous execution, we should see that the string text should be displayed before the call result. The program result is displayed as follows, indicating that the call is successful.
4. Client2: console application. This client is a client proxy class generated by using the svcutil.exe tool. Enter the command in the command line to generate UserInfoClient. cs and App. config.
Copy to the project directory of Client2,The Code Implementation of Program. cs is the same as that in client1.
5. Client3: console application. In this client, we use ChannelFactory <TChannel> to asynchronously call the service.Think about it: if we reference the service contract assembly,
However, our service contract does not define asynchronous service methods. How can we call them?Therefore, the use of ChannelFactory <TChannel> Method for asynchronous calls to the service is better than synchronous
One more step is to rewrite the service contract method on the client, instead of referencing the service contract assembly, just like the proxy method. The Code is as follows:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")][System.ServiceModel.ServiceContractAttribute(ConfigurationName="IUserInfo")]public interface IUserInfo{ [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IUserInfo/GetInfo", ReplyAction="http://tempuri.org/IUserInfo/GetInfoResponse")] Service.User[] GetInfo(System.Nullable<int> id); [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IUserInfo/GetInfo", ReplyAction="http://tempuri.org/IUserInfo/GetInfoResponse")] System.IAsyncResult BeginGetInfo(System.Nullable<int> id, System.AsyncCallback callback, object asyncState); Service.User[] EndGetInfo(System.IAsyncResult result);}
In this way, I can call the service operation method asynchronously, but the ChannelFactory <TChannel> method does not support the event-driven model, so we can use the callback function to call its service method.
Next, we complete the Client3 code operation.
Step 1: Use svcutil.exe to generate the client class. Run the following command to copy the generated file to the project directory of client3.
Step 2: implement the Client3 Program. cs code. The Code is as follows:
Using System; using System. collections. generic; using System. linq; using System. text; using System. serviceModel; using System. serviceModel. channels; using System. runtime. serialization; using Service; namespace Client3 {class Program {static void Main (string [] args) {EndpointAddress address = new EndpointAddress (" http://localhost:1234/UserInfo "); WSHttpBinding binding = new WSHttpBinding (); ChannelFactory <IUserInfo> factory = new ChannelFactory <IUserInfo> (binding, address); IUserInfo channel = factory. createChannel (); IAsyncResult ar = channel. beginGetInfo (null, GetInfoCallback, channel); Console. writeLine ("this string is output before calling the method, indicating that the asynchronous call is successful! "); Console. read ();} static void GetInfoCallback (IAsyncResult ar) {IUserInfo m_service = ar. asyncState as IUserInfo; User [] Users = m_service.EndGetInfo (ar); Console. writeLine ("{0,-10} {1,-10} {2,-10} {3,-10}", "ID", "Name ", "Age", "Nationality"); for (int I = 0; I <Users. length; I ++) {Console. writeLine ("{0,-10} {1,-10} {2,-10} {3,-10}", Users [I]. ID. toString (), Users [I]. name. toString (), Users [I]. age. toString (), Users [I]. nationality. toString ());}}}}
- Conclusion: we can see that the asynchronous service calling method on the client is similar to synchronous, but the implementation mechanism is different. If you want to better understand the code, I suggest you learn about IAsyncResult. I will explain this part in my post.