wcf例子:提供两个服务--发布订阅+并发

勇哥:

这个例子在一个服务进程内同时提供了两个服务client, mess。

一个用于api调用,一个用于发布订阅。



image.png


下面是工程列表:

image.png


下面是host宿主的app.config

两个服务的绑定一个是用管道,一个是tcp

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        
        <behavior name="SampleMethodbehavior">
          <serviceDebug httpHelpPageEnabled="false"/>
          <serviceMetadata httpGetEnabled="false"/>
          <serviceTimeouts transactionTimeout="00:10:00"/>
          <serviceThrottling maxConcurrentCalls="1000" maxConcurrentInstances="1000" maxConcurrentSessions="1000"/>
        </behavior>

        <behavior name="MessageFunbehavior">
          <serviceDebug httpHelpPageEnabled="false"/>
          <serviceMetadata httpGetEnabled="false"/>
          <serviceTimeouts transactionTimeout="00:10:00"/>
          <serviceThrottling maxConcurrentCalls="1000" maxConcurrentInstances="1000" maxConcurrentSessions="1000"/>
        </behavior>
        
        
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <netTcpBinding>
      
        <binding name="tcpbinding2">
          <security mode="None">
            <transport clientCredentialType="None" protectionLevel="None"/>
          </security>
        </binding>
      </netTcpBinding>
    </bindings>
    
    <services>


      <!--<services>
        <service name="HardwareLayerService.DMCAPI.MotionCardAPI" behaviorConfiguration="MotionCardAPI">
          <host>
            <baseAddresses>
              <add baseAddress="net.pipe://localhost/WCFService"/>
            </baseAddresses>
          </host>
          <endpoint address="" binding="netNamedPipeBinding" bindingConfiguration="" contract="HardwareLayerService.Interface.IMotionCardAPI"/>
          <endpoint address="mex" binding="mexNamedPipeBinding" contract="IMetadataExchange"/>
        </service>
      </services>-->
      
      <service name="ClassLibrary1.SampleMethod" behaviorConfiguration="SampleMethodbehavior">
        <host>
          <baseAddresses>
            <add baseAddress="net.pipe://localhost/SampleMethod"/>
          </baseAddresses>
        </host>
        <endpoint address="" binding="netNamedPipeBinding" bindingConfiguration="" contract="ClassLibrary1.ISampleMethod"/>
        <endpoint address="mex" binding="mexNamedPipeBinding" contract="IMetadataExchange"/>
      </service>
      
      

      <service name="ClassLibrary2.MessageFun" behaviorConfiguration="MessageFunbehavior">
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost:11113/MessageFun"/>
          </baseAddresses>
        </host>
        <endpoint address="" binding="netTcpBinding" bindingConfiguration="tcpbinding2" contract="ClassLibrary2.IMessageFun"/>
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
      </service>

    </services>
  </system.serviceModel>
</configuration>


宿主host是个winform程序

NotifyAll  用于服务端发送消息

Refresh  用于刷新客户端的连接

image.png


窗体的源码:

using ClassLibrary1;
using ClassLibrary2;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private List<ServiceHost> hosts = new List<ServiceHost>();
        private SampleMethod pubsrv = new SampleMethod();
        private MessageFun mess = new MessageFun();

        public Form1()
        {
            InitializeComponent();
        }

        private void btn_NotifyAll_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < mess.list_SubscrberId.Count; i++)
            {
                try
                {
                    mess.list_Callback[i].Notify(mess.list_SubscrberId[i].ToString());
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Data.ToString() + "\n无法连接客户:\n" + mess.list_SubscrberId[i].ToString());
                }
            }
        }

        private void btn_Refresh_Click(object sender, EventArgs e)
        {
            listBox_SubsciberID.Items.Clear();
            for (int i = 0; i < mess.list_SubscrberId.Count; i++)
                listBox_SubsciberID.Items.Add(mess.list_SubscrberId[i].ToString());
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //pubsrv);
            //host = new ServiceHost(pubsrv); // typeof(SampleMethod));
            //host.Open();

                        //(注1)
            hosts.Add(new ServiceHost(typeof(SampleMethod)));
            hosts.Add(new ServiceHost(mess));

           
            foreach (var host in hosts)
            {
                host.Opening += (s, e1) => { Console.WriteLine($"服务[{host.GetType().Name}]已经打开了"); };
                host.Open();
            }
            
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            foreach (var m in hosts)
            {
                m.Close();
            }
        }
    }
}

(注1)

注意下面的添加服务的方式,影响是否能并发.

typeof和直接使用服务的实例是不一样的。如果想并发必须使用typeof的写法。

ServiceHost(typeof(SampleMethod))
ServiceHost(mess)



下面是Service的源码。

Service是服务与契约。即接口与它的实现类。


IMessageFun.cs

这个是发布订阅功能的契约。

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace ClassLibrary2
{
    //SessionMode = SessionMode.Required,
    [ServiceContract( CallbackContract = typeof(ICallbackEvents))]
    public interface IMessageFun
    {
        [OperationContract(IsOneWay = true)]
        void Subscribe(Guid id);
        [OperationContract(IsOneWay = true)]
        void UnSubscribe(Guid id);
    }

    public interface ICallbackEvents
    {
        [OperationContract(IsOneWay = true)]
        void Notify(string msg);
    }


}

MessageFun.cs

Subscribe是订阅

UnSubscribe是取消订阅

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace ClassLibrary2
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
      ConcurrencyMode = ConcurrencyMode.Single)]
    public class MessageFun : IMessageFun
    {
        public List<Guid> list_SubscrberId = new List<Guid>();
        public List<ICallbackEvents> list_Callback = new List<ICallbackEvents>();

        public void Subscribe(Guid id)
        {
            if (list_SubscrberId.IndexOf(id) < 0)//如果不存在,则添加
            {
                list_SubscrberId.Add(id);
                ICallbackEvents callback = OperationContext.Current.GetCallbackChannel<ICallbackEvents>();
                list_Callback.Add(callback);
            }
        }

        public void UnSubscribe(Guid id)
        {
            list_Callback.RemoveAt(list_SubscrberId.IndexOf(id));
            list_SubscrberId.Remove(id);

        }
    }
}

ISampleMethod.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace ClassLibrary1
{

    [ServiceContract(SessionMode = SessionMode.Allowed)]
    public interface ISampleMethod
    {
        [OperationContract]
        string MethodOne(string msg);

        [OperationContract]
        string MethodTwo(string msg);

    }

    
}

SampleMethod.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ClassLibrary1
{
    [ServiceBehavior(UseSynchronizationContext = false,
        InstanceContextMode = InstanceContextMode.PerSession, 
        ConcurrencyMode = ConcurrencyMode.Multiple)]
    //[ServiceBehavior(UseSynchronizationContext = false)]
    public class SampleMethod : ISampleMethod
    {
        public string MethodOne(string msg)
        {
            OperationContext operationContext = OperationContext.Current;
            InstanceContext instanceContext = operationContext.InstanceContext;
            string info = "InstanceContext HashCode: " + instanceContext.GetHashCode().ToString();
            System.Threading.Thread.Sleep(5000);
            return msg + "\n->" + info + "\n->ManagedThreadId:" + Thread.CurrentThread.ManagedThreadId.ToString() + "  " + System.DateTime.Now.ToString();
        }

        public string MethodTwo(string msg)
        {
            OperationContext operationContext = OperationContext.Current;
            InstanceContext instanceContext = operationContext.InstanceContext;
            string info = "InstanceContext HashCode: " + instanceContext.GetHashCode().ToString();
            //System.Threading.Thread.Sleep(2000);
            return  msg + "\n->" + info + "\n->ManagedThreadId:" + Thread.CurrentThread.ManagedThreadId.ToString() + "  " + System.DateTime.Now.ToString();
        }

      
      

    }
}


下面是客户端的ui

要使用发布订阅,先点击“订阅”,然后去服务端点击Refresh,再点击 NotifyAll 。

另外几个按钮测试并发。

image.png

窗口源码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using WindowsFormsApp1.client;
using WindowsFormsApp1.mess;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        private Guid Myid;
        private Guid Myid2;
        private client.SampleMethodClient myclinet1=null;
        private client.SampleMethodClient myclinet2=null;
        private mess.MessageFunClient messClient;
        
        public Form1()
        {
            InitializeComponent();

            Myid = System.Guid.NewGuid();
            Myid2= Guid.NewGuid();
            CallbackEvents callback = new CallbackEvents();
            InstanceContext context = new InstanceContext(callback);
            messClient = new mess.MessageFunClient(context);

            myclinet1 = new client.SampleMethodClient();
            myclinet2 = new client.SampleMethodClient();


        }

        private void button1_Click(object sender, EventArgs e)
        {
            Task.Factory.StartNew(() =>
            {
                myclinet1.MethodOneAsync(new client.MethodOneRequest("c1_1"));
                myclinet1.MethodOneCompleted -= Myclinet1_MethodOneCompleted;
                myclinet1.MethodOneCompleted += Myclinet1_MethodOneCompleted;

                myclinet1.MethodTwoAsync(new client.MethodTwoRequest("c1_2"));
                myclinet1.MethodTwoCompleted -= Myclinet1_MethodTwoCompleted;
                myclinet1.MethodTwoCompleted += Myclinet1_MethodTwoCompleted;

                myclinet2.MethodOneAsync(new client.MethodOneRequest("c2_1"));
                myclinet2.MethodOneCompleted -= Myclinet2_MethodOneCompleted;
                myclinet2.MethodOneCompleted += Myclinet2_MethodOneCompleted;

                myclinet2.MethodTwoAsync(new client.MethodTwoRequest("c2_2"));
                myclinet2.MethodTwoCompleted -= Myclinet2_MethodTwoCompleted;
                myclinet2.MethodTwoCompleted += Myclinet2_MethodTwoCompleted;
            });
           
        }

        private void Myclinet2_MethodTwoCompleted(object sender, client.MethodTwoCompletedEventArgs e)
        {
            OutMsg(e.Result.MethodTwoResult.ToString());
        }

        private void Myclinet2_MethodOneCompleted(object sender, client.MethodOneCompletedEventArgs e)
        {
            OutMsg(e.Result.MethodOneResult.ToString());
        }

        private void Myclinet1_MethodTwoCompleted(object sender, client.MethodTwoCompletedEventArgs e)
        {
            OutMsg(e.Result.MethodTwoResult.ToString());
        }

        private void Myclinet1_MethodOneCompleted(object sender, client.MethodOneCompletedEventArgs e)
        {
            OutMsg(e.Result.MethodOneResult.ToString());
        }

        public void OutMsg(string str)
        {
            if (RtbMsg.IsDisposed) return;
            if (!RtbMsg.IsHandleCreated) return;
            if(RtbMsg.InvokeRequired)
            {
                Action<string> act = OutMsg;
                RtbMsg.Invoke(act, new object[] { str  });
            }
            else
            {
                RtbMsg.AppendText(str+"\n");
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            myclinet1.MethodOneAsync(new client.MethodOneRequest("c1_1"));
            myclinet1.MethodOneCompleted -= Myclinet1_MethodOneCompleted;
            myclinet1.MethodOneCompleted += Myclinet1_MethodOneCompleted;
           
        }

        private void button3_Click(object sender, EventArgs e)
        {
            myclinet1.MethodTwoAsync(new client.MethodTwoRequest("c1_2"));
            myclinet1.MethodTwoCompleted -= Myclinet1_MethodTwoCompleted;
            myclinet1.MethodTwoCompleted += Myclinet1_MethodTwoCompleted;
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void button4_Click(object sender, EventArgs e)
        {
            if (myclinet1 == null)
            {
                CallbackEvents callback = new CallbackEvents();
                InstanceContext context = new InstanceContext(callback);
                messClient = new mess.MessageFunClient(context);
            }
            messClient.Subscribe(new Subscribe() { id = Myid });
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                myclinet1.Close();
                myclinet2.Close();
                messClient.Close();
            }
            catch
            {
                myclinet1.Abort();
                myclinet2.Abort();
                messClient.Abort();
            }
        }
    }

    class CallbackEvents :mess.IMessageFunCallback
    {
        public IAsyncResult BeginNotify(Notify request, AsyncCallback callback, object asyncState)
        {
            throw new NotImplementedException();
        }

        public void EndNotify(IAsyncResult result)
        {
            throw new NotImplementedException();
        }

        public void Notify()
        {
            
            MessageBox.Show("Subscibe Ok");
        }

        public void Notify(Notify request)
        {
            MessageBox.Show($"Subscibe Ok2 [{request.msg}]");
        }
    }

}



本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:
本帖最后由 勇哥,很想停止 于 2024-04-06 20:06:15 编辑

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2024年4月    »
1234567
891011121314
15161718192021
22232425262728
2930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864