• WCF-异步调用和两种客户端形式


        当发布一个服务端之后,客户端可以通过服务端的元数据,用VS2010添加服务引用的方式生成对应的代码。并且可以选择生成相应的异步操作。

    WCF实现代码,Add操作延时5秒后再返回结果。

    [ServiceContract]
        public interface ICalculator
        {
            [OperationContract]
            int Add(int x, int y);
        }
    
        [ServiceBehavior]
        public class Cal : ICalculator
        {
            public int Add(int x, int y)
            {
                System.Threading.Thread.Sleep(5000);
                return x + y;
            }
        }
    

     服务寄宿:

     static void Main(string[] args)
            {
                ServiceHost host = new ServiceHost(typeof(kk.Cal));
                ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
                behavior.HttpGetUrl = new Uri("http://localhost:6666/meta");
                behavior.HttpGetEnabled = true;
                host.Description.Behaviors.Add(behavior);
                host.AddServiceEndpoint(typeof(kk.ICalculator), new WSHttpBinding(), "http://localhost:6666");
                host.Opened+=delegate{Console.WriteLine("Service start!");};
                host.Open();
                Console.ReadLine();
            }
    

     通过ServiceMetadataBehavior的HttpGetUrl可以设置服务的元数据地址,客户端通过这个地址获取到服务的全部信息。

    先运行服务端。再按下列步骤在客户端添加服务引用

    1.添加服务引用

    2.输入服务公布的元数据地址。

    3.在高级中选中生成异步操作。再点击2中的前往即可。

    一、通过BeginAdd/EndBegin方法调用客户端。

    生成成功后通过默认命名空间ServiceReference1获取到客户端,直接调用BeginAdd方法进行异步调用。

    static void Main(string[] args)
            {
                 ServiceReference1.CalculatorClient client = new ServiceReference1.CalculatorClient();
                client.BeginAdd(1, 2, CallBack, client);
                for (int i = 0; i < 100; i++)
                {
                    System.Threading.Thread.Sleep(1000);
                    Console.WriteLine("{0}", i);
                }
            }
    
            public static void CallBack(IAsyncResult ar)
            {
                ServiceReference1.CalculatorClient client = ar.AsyncState as ServiceReference1.CalculatorClient;
                int result = client.EndAdd(ar);
                Console.WriteLine("Result:{0}", result);
            }
    

    BeginAdd的前两个参数是契约接口参数。第三个是回调方法,参数类型为IAsyncResult返回值为void的委托。第四个是Object类,这里将client客户端传进去,因为需要在回调方法中调用EndAdd方法得到结果。或者直接把client定义成static成员变量,这样就不需要传入了。

    二、通过xxxCompleted添加委托。

    static void Main(string[] args)
            {
                 ServiceReference1.CalculatorClient client = new ServiceReference1.CalculatorClient();
                 client.AddCompleted += delegate(object sender, ServiceReference1.AddCompletedEventArgs e)
                 {
                   int[] para =   e.UserState as int[];
                   int result = e.Result;
                   Console.WriteLine("Result:{0}+{1}={2}", para[0], para[1], result);
                 };
                client.AddAsync(1, 2,new int[]{1,2});
                for (int i = 0; i < 100; i++)
                {
                    System.Threading.Thread.Sleep(1000);
                    Console.WriteLine("{0}", i);
                }
            }
    

     Completed+=委托是上面的一种变形,直接通过completedEventArgs的Result属性获取结果,UserState获取附加参数。

    上面两种异步调用实现效果为:

    通过观察在客户端通过添加服务引用生成的代码,

    public partial class CalculatorClient : System.ServiceModel.ClientBase<client2.ServiceReference1.ICalculator>, client2.ServiceReference1.ICalculator

    发现ServiceReference1.CalculatorClient是继承自

    public abstract class ClientBase<TChannel> : ICommunicationObject, IDisposable where TChannel : class

    这也意味着我们可以自定义一个Cinent,而不需要去生成而产生很多无用的代码。

    using System.ServiceModel;
    using System.ServiceModel.Channels;
    namespace client2
    {
        class Program
        {
            static void Main(string[] args)
            {
                myClient client = new myClient(new WSHttpBinding(), new EndpointAddress(new Uri("http://localhost:6666")));
                int result=client.myChannel.Add(1, 2);
                Console.WriteLine("{0}", result);
            }
        }
    
        public class myClient : ClientBase<kk.ICalculator>
        {
            public myClient(Binding bind, EndpointAddress addr)
                : base(bind, addr)
            { 
            }
            public kk.ICalculator myChannel
            {
                get 
                {
                    return this.Channel;
                }
            }
        }
    }
    

     myClient继承ClientBase并指定泛型契约,重写基类构造函数,指定Binding和EndpointAddress。并通过返回基类Channel属性。构造的时候传入服务端使用的绑定模式,和终结点地址。然后通过myChannel即可获取通道。其实这个ClientBase内部也是通过ChannelFactory<T>实现的,通过信道工厂创建信道,通过信道调用服务端方法。下面代码是通过信道工厂实现。

    static void Main(string[] args)
            {
                ChannelFactory<kk.ICalculator> factory = new ChannelFactory<kk.ICalculator>(new WSHttpBinding(), new EndpointAddress(new Uri("http://localhost:6666")));
                kk.ICalculator mychannel=factory.CreateChannel();
                mychannel.Add(1, 2);
            }
    
  • 相关阅读:
    一、K3 WISE 插件开发《常用数据表整理》
    数据类型
    python的一些操作命令
    python基本数据类型
    20181207朱涛《网络对抗技术》Exp8 Web综合
    20181207朱涛《网络对抗技术》Exp7 网络欺诈防范
    20181207朱涛《网络对抗技术》Exp6 MSF应用基础
    20181207朱涛《网络对抗技术》Exp5 信息搜集与漏洞扫描
    20181207朱涛《网络对抗技术》Exp4 恶意代码分析
    20181207朱涛《网络对抗技术》Exp3 免杀原理
  • 原文地址:https://www.cnblogs.com/lh218/p/4405251.html
Copyright © 2020-2023  润新知