前言:
WCF客户端异步调用服务方式:
WCF客户端异步调用服务实例:
IUserInfo.cs的代码如下:
class="code_img_closed" src="/Upload/Images/2015041010/0015B68B3C38AA5B.gif" alt="" />logs_code_hide('46998397-f252-4057-bf8e-e30bf3c2dc5c',event)" src="/Upload/Images/2015041010/2B1B950FA3DF188F.gif" alt="" />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
UserInfo.cs的代码如下:
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:控制台应用程序,添加对Service程序集的引用,寄宿服务程序。
Program.cs代码如下
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("服务已经启动,按任意键终止!"); }; host.Open(); Console.Read(); } } } }View Code
App.config代码如下:
<?xml version="1.0"?> <configuration> <system.serviceModel> <services> <service name="Service.UserInfo" behaviorConfiguration="mexBehavior"> <host> <baseAddresses> <add baseAddress="http://localhost:1234/UserInfo/"/> </baseAddresses> </host> <endpoint address="" binding="wsHttpBinding" contract="Service.IUserInfo" /> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="mexBehavior"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="true"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>View Code
3. Client1:控制台应用程序。添加对服务终结点地址http://localhost:1234/UserInfo/的引用,设置服务命名空间为UserInfoServiceRef,点击高级设置,勾选生成异步操作选项,
生成客户端代理类和配置文件代码后,完成Client1对服务的调用。
Program.cs的代码如下:
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("此字符串在调用方法前输出,说明异步调用成功!"); 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
从上面的代码可以看出客户端代理类调用采用了事件驱动机制,服务的方法GetInfo()与基于事件的异步调用方法一起使用且形式为GetInfoCompleted 的操作完成事件。客户端具体实现在proxy_GetInfoCompleted事件里,通过参数类型GetInfoCompletedEventArgs的Result可以获得返回结果。而proxy.GetInfoAsync(null)代码说明服务开始异步调用。在此客户端我特地输出了Console.WriteLine("此字符串在调用方法前输出,说明异步调用成功!")一串文字来证明服务是异步调用的。因为在操作契约GetInfo()的方法中,我让程序线程休眠了1s,模拟程序执行的时间。如果客户端调用服务异步执行,我们应该会看到字符串文字应该显示在调用结果的前面。程序结果显示如下,说明结果调用成功。
4. Client2: 控制台应用程序。此客户端我们是通过svcutil.exe工具生成的客户端代理类。在命令行中输入以下图中的命令,将生成的UserInfoClient.cs和App.config
复制到Client2的工程目录下,Program.cs的代码实现和Client1中的一样。
5. Client3: 控制台应用程序。在此客户端中,我们将通过ChannelFactory<TChannel>的方式对服务进行异步调用。想一想:我们如果对服务契约进行程序集引用,
可是我们的服务契约并没有异步服务方法的定义,那我们怎么来调用服务方法呢?所以使用ChannelFactory<TChannel>的方式对服务进行异步调用就要比同步的
方式多一个步骤,那就是我们必须在客户端对服务契约的方法进行重写,而不是对服务契约程序集的引用,就像代理方式一样。代码参考如下:
[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); }
这样我可以对服务的操作方法进行异步调用了,但是ChannelFactory<TChannel>的方式不支持事件驱动模型,所以我们可以利用回调函数来对其服务方法进行调用。
接下来,我们完成Client3的代码操作。
第一步:利用svcutil.exe生成客户端类,我们输入一下命令,将生成的文件复制到Client3的工程目录下。
第二步:实现Client3的Program.cs的代码。代码如下:
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("此字符串在调用方法前输出,说明异步调用成功!"); 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()); } } } }