wcf的 ChannelFactory的使用及常见错误

在学习和测试 WCF 的时候,我通常使用 ChannelFactory 来代替 Client Proxy。

原因是方便,无须创建多个 Project / Class。

当然,在正式开发中还是使用 Client Proxy 要好些,毕竟 ChannelFactory 直接依赖于契约,违背了 SOA 边界隔离的原则。

使用 ChannelFactory 很简单,但完成方法后要及时调用 Close 或 Dispose,以便服务器及时释放服务实例。

其实该对象还实现了另外两个接口 —— IDisposable 和 ICommunicationObject。


下面是演示代码:

注意下面代码中使用代码创建了EndPoint终结点信息,因此它不需要你手工配置服务器和客户端的app.config。

[ServiceContract]
public interface IContract
{
  [OperationContract]
  void Test(int i);
}

public class MyService : IContract
{
  public void Test(int i)
  {
    Console.WriteLine(i);
  }
}

public class WcfTest
{
  public static void Test()
  {
    AppDomain.CreateDomain("Server1").DoCallBack(delegate
    {
      ServiceHost host = new ServiceHost(typeof(MyService), new Uri("http://localhost:8080/MyService"));
      host.AddServiceEndpoint(typeof(IContract), new BasicHttpBinding(), "");
      host.Open();
    });

    IContract channel = ChannelFactory<IContract>.CreateChannel(new BasicHttpBinding(), new EndpointAddress("http://localhost:8080/MyService"));

    using (channel as IDisposable)
    {
      ICommunicationObject o = channel as ICommunicationObject;

      o.Opening += delegate { Console.WriteLine("Opening..."); };
      o.Closing += delegate { Console.WriteLine("Closing..."); };

      channel.Test(1);
    }
  }
}


以上代码只是功能演示,实际使用时会有一些问题。

比如下面这个报错:

"在 ServiceModel 客户端配置部分中,找不到名称“CalMethod1”和协定“ClassLibrary1.ICal”的终结点元素。

这可能是因为未找到应用程序的配置文件,或者是因为客户端元素中找不到与此名称匹配的终结点元素。"

image.png


其原因是你在客户端没有配置好app.config。

当你使用VS的添加服务引用时,系统会自动在客户端的app.config里写上必要的配置,你会有一种错觉是不需要配置客户端的app.config了。


下面是客户端的配置。

注意其中那个endpoint终结点务必要配置一个name属性。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>


  <system.serviceModel>
    <bindings>
      <netNamedPipeBinding>
        <binding name="CalMethod" />
      </netNamedPipeBinding>
    </bindings>
    <client>
      <endpoint address="net.pipe://localhost/CalMethod" binding="netNamedPipeBinding"
          bindingConfiguration="CalMethod" contract="ClassLibrary1.ICal"
          name="CalMethod">
        <identity>
          <userPrincipalName value="liuxiaoyong@samsuncn.com" />
        </identity>
      </endpoint>
    </client>
  </system.serviceModel>
</configuration>


下面是Host端的配置:

可以看到它的endpoint终结点是可以不要name属性的。

<?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="CalMethod">
          <serviceDebug httpHelpPageEnabled="false"/>
          <serviceMetadata httpGetEnabled="false"/>
          <serviceTimeouts transactionTimeout="00:10:00"/>
          <serviceThrottling maxConcurrentCalls="1000" maxConcurrentInstances="1000" maxConcurrentSessions="1000"/>
        </behavior>
      
      </serviceBehaviors>
    </behaviors>

    <services>

      <service name="ClassLibrary1.CalMethod" behaviorConfiguration="CalMethod">
        <host>
          <baseAddresses>
            <add baseAddress="net.pipe://localhost/CalMethod"/>
          </baseAddresses>
        </host>
        <endpoint address="" binding="netNamedPipeBinding" bindingConfiguration="" contract="ClassLibrary1.ICal"/>
        <endpoint address="mex" binding="mexNamedPipeBinding" contract="IMetadataExchange"/>
      </service>
     
    </services>
  </system.serviceModel>
</configuration>



客户端代码:

image.png

using ClassLibrary1;
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
    {
        ChannelFactory<ICal> fac = null;
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            fac = new ChannelFactory<ICal>("CalMethod1");
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ICal proxy = fac.CreateChannel();
            using (proxy as IDisposable)
            {
                ICommunicationObject com = proxy as ICommunicationObject;
                com.Opening += delegate { richTextBox1.AppendText($"Opening...\n");  };
                com.Closing += delegate { richTextBox1.AppendText($"Closing...\n"); };
                richTextBox1.AppendText($"{proxy.Cal(10, 5)}\n");
            }

        }
    }
}

Host端代码:

image.png

using ClassLibrary1;
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 ServiceHost host = null;
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                host.Open();
                richTextBox1.AppendText("服务已经打开");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            try
            {
                host.Close();
                richTextBox1.AppendText("服务已经关闭");
            }
            catch
            {
                host.Abort();
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            host = new ServiceHost(typeof(CalMethod));
            this.Disposed += delegate
             {
                 host.Close();
             };
        }

       
    }
}


service端代码:

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

namespace ClassLibrary1
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class CalMethod : ICal
    {

        int ICal.Cal(int a, int b)
        {
            return a + b;
        }
    }
}
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 ICal
    {
        [OperationContract]
        int Cal(int a, int b);
    }
}


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

发表评论:

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

会员中心
搜索
«    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