• WCF服务使用(IIS+Http)和(Winform宿主+Tcp)两种方式进行发布


    1、写在前面
    刚接触WCF不久,有很多地方知其然不知其所以然。当我在【创建服务->发布服务->使用服务】这一过程出现过许多问题。如客户端找不到服务引用;客户端只在本机环境中才能访问服务,移植到其他机器上就不能访问服务(权限问题)等问题。所以写下这篇文章把我使用http和tcp这两方式部署服务所出现的问题以及解决方案记录下来,方便自己下次查看,也可以当作初学WCF的一个入门小示例吧。
     
    2、建立一个WCF服务
    首先要编写一个WCF服务,我在这里提供一个通过名字查询年龄的服务,代码如下:
    服务契约:
        [ServiceContract]
        public interface IPeopleInfo
        {
            [OperationContract]
            int GetAge(string name);
        }

     数据契约:

        [DataContract]
        public class People
        {
            public string Name;
            public int Age;
        }

    服务实现:

        public class PeopleInfo : IPeopleInfo
        {
    
            public int GetAge(string name)
            {
                List<People> peopleList = DataFactory.GetPeopleList();
                return peopleList.Find(t =>t.Name==name).Age ;
            }
        }

     辅助类:

        public class DataFactory
        { 
            public static List<People> GetPeopleList()
            {
                List<People> peopleList = new List<People>();
                peopleList.AddRange(new People[] { 
                    new People{Name="tjm",Age=18},
                    new People{Name="lw",Age=20},
                    new People{Name="tj",Age=22},
                });
                return peopleList;
            }
        }
    2、发布(部署)服务
    在这里使用两种方式发布服务。一:利用iis作为宿主,使用http通信协议发布服务;二:利用Winform程序作为宿主,使用tcp通信协议发布服务。
     
    2.1、iis作为宿主,使用http通信协议发布服务
    把1中已经编写好的服务,可以像部署一个WebService或者是Asp.Net网站一样部署到局域网上去。这里的发布服务的步骤就省略了。发布成功之后在浏览器中进行访问时出现如下的错误:
    WCF部署IIS出现“由于扩展配置问题而无法提供您请求的页面。如果该页面是脚本,请添加处理程序。如果应下载文件,请添加 MIME 映射”的解决办法
    网上有找了很多资料,大部分的解决方案都是说,系统没有默认iis注册WCF服务的svc文件的MIME映射,于是我为iis注册WCF服务的映射,方法如下:

    管理员身份运行C:WindowsMicrosoft.NETFrameworkv3.0Windows Communication FoundationServiceModelReg.exe -i

    但是注册完之后,在浏览器中浏览该网站还是出现错误,错误如下:
    HTTP 错误 404.3 - Not Found,
    于是在网上又找到解决方案如下:
    使用管理员注册:C:Windowssystem32>"C:WindowsMicrosoft.NETFrameworkv4.0.30319ServiceModelReg.exe" -r
    注册完之后直接在控制台中出现如下错误,

    Microsoft(R) WCF/WF 注册工具版本 4.5.0.0

    版权所有(C) Microsoft Corporation。保留所有权利。

    用于管理一台计算机上 WCF 和 WF 组件的安装和卸载的管理实用工具。

    [错误]此 Windows 版本不支持此工具。管理员应改为使用“打开或关闭 Windows 功能”对话框或 dism 命令行工具来安装/卸载 Windows Communication Foundation 功能。

    根据错误的提示,去控制面板->程序->启用或关闭Windows功能,如下图

     

     把我画红线的框内的复选框全部勾选,点击确定,然后再在iis中再进行浏览就能够找到发布后的WCF服务了,原因应该是我没有安装WCF服务的组件而导致的吧。在浏览器中浏览服务如下。

    如果上述的方法,还没有在iis中成功发布服务,可以尝试。
    在window功能中卸载iis和WCF服务,然后再重新安装配置。
    到此,使用iis中利用http协议发WCF服务已经成功了。
     
    2.2 利用Winform程序作为宿主,使用tcp通信协议发布服务

    首先建立一个Winform项目,界面如下。

    在这里使用两种方式来宿主WCF服务,第一用代码的方式,第二使用配置文件的方式。
    注意:在部署之前需要把第一步中编写服务的dll引用进来。
    1)使用代码部署WCF服务
    代码如下:
            ServiceHost host;
            private void btnStart_Click(object sender, EventArgs e)
            {
                //使用代码绑定
                Uri tcpa = new Uri("net.tcp://172.21.212.54:8090/peopleinfo");
                host = new ServiceHost(typeof(FirstWCFService.PeopleInfo), tcpa);
                ServiceMetadataBehavior mBehave = new ServiceMetadataBehavior();
                NetTcpBinding tcpb = new NetTcpBinding();
                host.Description.Behaviors.Add(mBehave);
                host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
                host.AddServiceEndpoint(typeof(FirstWCFService.IPeopleInfo), tcpb, tcpa);
    
                host.Open();
    this.btnStart.Enabled = false;
                this.label1.Text = "Service Running";
    }
    private void btnStop_Click(object sender, EventArgs e) { if (host != null) { host.Close(); this.label1.Text = "Service Closed"; this.btnStart.Enabled = true; } }

    2)使用配置文件

    其实使用配置文件和使用代码理论是差不多的,可以根据代码编写配置文件,上面的代码分析可知道,服务宿主对象host添加了一个ServiceMetadataBehavior 对象和两个Endpoint,因此App.config配置文件中的内容如下。
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
        <services>
          <service name="FirstWCFService.PeopleInfo">
            <!--客户端用来解释服务,这个端点如果缺少服务会发布失败-->
            <endpoint contract="IMetadataExchange"
               binding="mexTcpBinding" address ="net.tcp://172.21.212.54:8090/peoleinfo/mex"></endpoint>
            <!--提供服务的端点-->
            <endpoint address="net.tcp://172.21.212.54:8090/peoleinfo" binding="netTcpBinding"
                contract="FirstWCFService.IPeopleInfo">
    
            </endpoint>
          </service>
        </services>
        <behaviors>
          <serviceBehaviors>
            <behavior>
              <serviceMetadata/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>
    </configuration>

     虽然是用来配置文件,但是开启服务的代码还是需要写的。代码如下。

            ServiceHost host;
            private void btnStart_Click(object sender, EventArgs e)
            {
                host = new ServiceHost(typeof(FirstWCFService.PeopleInfo));
                host.Open();
                this.btnStart.Enabled = false;
                this.label1.Text = "Service Running";
            }
    
            private void btnStop_Click(object sender, EventArgs e)
            {
                if (host != null)
                {
                    host.Close();
                    this.label1.Text = "Service Closed";
                    this.btnStart.Enabled = true;
                }
            }

     运行程序,点击Start按钮,到此使用Winform作为宿主来发布WCF服务已经成功了。

     
    3、编写客户端调用服务。
    客户端使用Winform程序,界面设计如下:
     
    然后分别添加使用http和tcp方式发布的wcf服务。
    1)引用iis+http协议发布的服务
    2)引用Winform宿主+tcp协议发布的服务
    服务添加完成之后,在项目中会自动生成一个应用程序的配置文件,里面记录了调用WCF服务的信息。配置文件内容如下:
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <system.serviceModel>
            <bindings>
                <basicHttpBinding>
                    <binding name="BasicHttpBinding_IPeopleInfo" />
                </basicHttpBinding>
                <netTcpBinding>
                    <binding name="NetTcpBinding_IPeopleInfo">
                    </binding>
                </netTcpBinding>
            </bindings>
            <client>
                <endpoint address="http://172.21.212.54/PeopleInfo.svc" binding="basicHttpBinding"
                    bindingConfiguration="BasicHttpBinding_IPeopleInfo" contract="HttpService.IPeopleInfo"
                    name="BasicHttpBinding_IPeopleInfo" />
                <endpoint address="net.tcp://172.21.212.54:8090/peoleinfo" binding="netTcpBinding"
                    bindingConfiguration="NetTcpBinding_IPeopleInfo" contract="TcpService.IPeopleInfo"
                    name="NetTcpBinding_IPeopleInfo" />
            </client>
        </system.serviceModel>
    </configuration>

     调用服务操作的代码非常简单,就类似于操作本地的类一样,代码如下: 

            private void bntGet_Click(object sender, EventArgs e)
            {
                string name = this.txtName.Text;
                int age;
                if (rdbHttp.Checked)
                {
                    HttpService.PeopleInfoClient httpClient = new HttpService.PeopleInfoClient();
                    age = httpClient.GetAge(name);
                }
                else
                {
                    TcpService.PeopleInfoClient tcpClient = new TcpService.PeopleInfoClient();
                    age = tcpClient.GetAge(name);
                }
                this.txtAge.Text = age.ToString();
            }

     到此,wcf的客户端编写完成,结果如下。

     
    注意:把wcf的客户端部署到其他机器上去运行,选择http进行调用没有问题,而选择tcp调用服务的时候会出现如下错误:

    System.ServiceModel.Security.SecurityNegotiationException: 服务器已拒绝客户端凭据。 --->

    System.Security.Authentication.InvalidCredentialException: 服务器已拒绝客户端凭据。 ---> 

    System.ComponentModel.Win32Exception: 登录没有成功
    其中http方式是由iis进行托管的,里面权限已经是配置好的,允许匿名用户进行访问,因此在远程访问时不会出现问题的。而tcp方式是由我们自己编写winform程序管理的,当客户端在本机时候,是因为它本身就具有window的用户访问的权限,因此可以访问,当部署到其他其他机器上去的时候,已经不具备本机的这种环境,所以当我们使用winform作为宿主的时候,要在配置文件中设置权限模式,在这里使用无需客户端验证的方式。在Winform宿主项目的配置文件添加如下内容,红色加粗标示为新增的。
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
        <services>
          <service name="FirstWCFService.PeopleInfo">
            <!--客户端用来解释服务,这个端点如果缺少服务会发布失败-->
            <endpoint contract="IMetadataExchange"
               binding="mexTcpBinding" address ="net.tcp://172.21.212.54:8090/peoleinfo/mex"></endpoint>
            <!--提供服务的端点-->
            <endpoint address="net.tcp://172.21.212.54:8090/peoleinfo" binding="netTcpBinding"
                contract="FirstWCFService.IPeopleInfo" bindingConfiguration="NoSecurity">
            </endpoint>
          </service>
        </services>
        <bindings>
          <netTcpBinding>
            <binding name="NoSecurity">
              <security mode="None"/>
            </binding>
          </netTcpBinding>
        </bindings>
        <behaviors>
          <serviceBehaviors>
            <behavior>
              <serviceMetadata/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>
    </configuration>

     设置完成之后,重新开启服务。然后在客户端删除winform宿主发布的服务,并且再重新添加,以便在配置文件中重新生成访问tcp方式的服务端点的配置。更新后的配置文件如下,红色加粗部分为更新的。

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <system.serviceModel>
            <bindings>
                <basicHttpBinding>
                    <binding name="BasicHttpBinding_IPeopleInfo" />
                </basicHttpBinding>
                <netTcpBinding>
                    <binding name="NetTcpBinding_IPeopleInfo">
                        <security mode="None" />
                    </binding>
                </netTcpBinding>
            </bindings>
            <client>
                <endpoint address="http://172.21.212.54/PeopleInfo.svc" binding="basicHttpBinding"
                    bindingConfiguration="BasicHttpBinding_IPeopleInfo" contract="HttpService.IPeopleInfo"
                    name="BasicHttpBinding_IPeopleInfo" />
                <endpoint address="net.tcp://172.21.212.54:8090/peoleinfo" binding="netTcpBinding"
                    bindingConfiguration="NetTcpBinding_IPeopleInfo" contract="TcpService.IPeopleInfo"
                    name="NetTcpBinding_IPeopleInfo" />
            </client>
        </system.serviceModel>
    </configuration>
    4、结论
    虽然WCF服务的两种部署方式已经成功了,但是其中有许多的原理还不是太明白,毕竟接触WCF还不久。希望后面继续深入的学习,达到知其然并且知其所以然境界。
     
  • 相关阅读:
    树状数组求区间最大值
    ABP Zero最新版源码
    abp zero mysql版正式发布
    基于ABP的Easyui admin framework正式开放源代码
    【推荐】ImageProcessor.Web,再也不用自己生成缩略图了
    ABP教程(四)- 开始一个简单的任务管理系统
    Abp Framework中文文档上线
    【开源】基于EF6+MVC5+API2+Easyui1.4.5+Easyui管理模板开发的管理系统
    web+ admin template,spa管理应用后台,easyui后台正式发布
    ABP教程(三)- 开始一个简单的任务管理系统 – 后端编码
  • 原文地址:https://www.cnblogs.com/mingjiatang/p/5476485.html
Copyright © 2020-2023  润新知