Windows Communication Foundation 开发指南1——启用元数据发布

发布于 2024-10-27 04:19:53 字数 18709 浏览 8 评论 0

0x00 前言

Windows Communication Foundation (WCF) 是用于在.NET Framework 中构建面向服务的应用程序的框架。本文将要介绍 WCF 开发的相关内容,为后续介绍的内容作铺垫。

0x01 简介

本文将要介绍以下内容:

  • 使用 basicHttpBinding 实现 WCF
  • 使用 NetTcpBinding 实现 WCF
  • 通过命令行实现 WCF
  • 通过 IIS 实现 WCF
  • 通过服务实现 WCF

0x02 基础知识

参考资料:https://docs.microsoft.com/en-us/dotnet/framework/wcf/whats-wcf

常用的传输协议:

常用的 Binding:

  • BasicHttpBinding
  • WSHttpBinding
  • NetTcpBinding
  • NetNamedPipeBinding

元数据发布(metadata exchange),简称 MEX

WCF 默认禁用 MEX,这样能够避免数据泄露

本着逐步深入的原则,本系列文章选择先介绍开启 MEX 的用法,这样能够提高客户端开发的效率,禁用 MEX 的用法将放在下篇文章进行介绍。

0x03 使用 basicHttpBinding 实现 WCF

本节采用命令行实现 WCF 的方式作为示例

开发工具:Visual Studio 2015

1.服务端编写

(1) 新建项目

选择 Visual C# -> Console Application ,名称为 basicHttpBindingWCFServer

(2) 新建 WCF 服务

选择 Add -> New Item... ,选择 WCF Service ,名称为 Service1.cs

(3) 修改 service1.cs

添加 DoWork 的实现代码,代码示例:

using System;
namespace basicHttpBindingWCFServer
{
    public class Service1 : IService1
    {
        public void DoWork()
        {
            Console.Write("Run Server.DoWork()");
        }
    }
}

(4) 修改 Program.cs

添加引用 System.ServiceModel

添加启动代码,代码示例:

using System;
using System.ServiceModel;
namespace basicHttpBindingWCFServer
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceHost Host = new ServiceHost(typeof(Service1));
            Host.Open();
            Console.WriteLine(Host.Description.Endpoints[0].Address);
            Console.ReadLine();
            Host.Close();
        }
    }
}

(5) 编译运行

命令行输出服务地址: http://localhost:8733/Design_Time_Addresses/basicHttpBindingWCFServer/Service1/

服务地址也可以在工程中的 App.config 查看

(6) 测试

此时开启了 MEX,可选择以下方法进行测试:

注:

App.config 由 Visual Studio 自动生成,服务地址由 App.config 随机指定,这里也可以通过代码的方式指定服务地址,不需要依赖 App.config,方法如下:

Program.cs 示例:

using System;
using System.ServiceModel;
using System.ServiceModel.Description;
namespace basicHttpBindingWCFServer
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceHost host = null;
            try
            {            
                Uri baseAddress = new Uri("http://localhost/TestService");
                host = new ServiceHost(typeof(Service1), baseAddress);
                BasicHttpBinding binding = new BasicHttpBinding();          
                host.AddServiceEndpoint(typeof(IService1), binding, baseAddress);
                if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
                {
                    ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
                    behavior.HttpGetEnabled = true;                    
                    host.Description.Behaviors.Add(behavior);
                }
                host.Open();
                Console.WriteLine(host.Description.Endpoints[0].Address);
                Console.Read();
                host.Close();      
            }
            catch (CommunicationException ce)
            {
                host.Abort();
            }
        }
    }
}

App.config 示例:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
  </startup>
</configuration>

2.客户端编写

(1) 新建项目

选择 Visual C# -> Console Application ,名称为 basicHttpBindingWCFClient

(2) 引用服务

选择 Add -> Service Reference...

填入 URL: http://localhost:8733/Design_Time_Addresses/basicHttpBindingWCFServer/Service1/

(3) 修改 Program.cs

代码示例:

using basicHttpBindingWCFClient.ServiceReference1;
namespace basicHttpBindingWCFClient
{
    class Program
    {
        static void Main(string[] args)
        {
            Service1Client service1 = new Service1Client();
            service1.DoWork();
        }
    }
}

(4) 编译运行

此时服务端命令行输出 Run Server.DoWork() ,方法调用成功

0x04 使用 NetTcpBinding 实现 WCF

本节采用命令行实现 WCF 的方式作为示例

1.服务端编写

(1) 新建项目

选择 Visual C# -> Console Application ,名称为 NetTcpBindingWCFServer

(2) 新建 WCF 服务

选择 Add -> New Item... ,选择 WCF Service ,名称为 Service1.cs

(3) 修改 service1.cs

添加 DoWork 的实现代码,代码示例:

using System;
namespace NetTcpBindingWCFServer
{
    public class Service1 : IService1
    {
        public void DoWork()
        {
            Console.Write("Run Server.DoWork()");
        }
    }
}

(4) 修改 Program.cs

添加引用 System.ServiceModel

添加启动代码,代码示例:

using System;
using System.ServiceModel;
namespace NetTcpBindingWCFServer
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceHost Host = new ServiceHost(typeof(Service1));
            Host.Open();
            Console.WriteLine(Host.Description.Endpoints[0].Address);
            Console.ReadLine();
            Host.Close();
        }
    }
}

(5) 修改 App.config

Line10: <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />

修改为: <serviceMetadata httpGetEnabled="false" httpsGetEnabled="false" />

Line17: <endpoint address="" binding="basicHttpBinding" contract="NetTcpBindingWCFServer.IService1">

修改为: <endpoint address="" binding="netTcpBinding" contract="NetTcpBindingWCFServer.IService1">

Line22: <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />

修改为: <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />

Line25: <add baseAddress="http://localhost:8733/Design_Time_Addresses/NetTcpBindingWCFServer/Service1/" />

修改为: <add baseAddress="net.tcp://localhost:1111/Design_Time_Addresses/NetTcpBindingWCFServer/Service1/" />

完整代码示例:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
    </startup>
    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="">
                    <serviceMetadata httpGetEnabled="false" httpsGetEnabled="false" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <services>
            <service name="NetTcpBindingWCFServer.Service1">
                <endpoint address="" binding="netTcpBinding" contract="NetTcpBindingWCFServer.IService1">
                    <identity>
                        <dns value="localhost" />
                    </identity>
                </endpoint>
                <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
                <host>
                    <baseAddresses>
                        <add baseAddress="net.tcp://localhost:1111/Design_Time_Addresses/NetTcpBindingWCFServer/Service1/" />
                    </baseAddresses>
                </host>
            </service>
        </services>
    </system.serviceModel>
</configuration>

(6) 编译运行

命令行输出服务地址:net.tcp://localhost:1111/Design_Time_Addresses/NetTcpBindingWCFServer/Service1/

(7) 测试

此时开启了 MEX,可选择以下方法进行测试:

  • 使用 WcfTestClient 进行测试,默认路径: C:\Program Files(x86)\Microsoft Visual Studio 14\Common7\IDE\WcfTestClient.exe ,连接 net.tcp://localhost:1111/Design_Time_Addresses/NetTcpBindingWCFServer/Service1/,调用 DoWork() ,此时服务端命令行输出 Run Server.DoWork() ,方法调用成功
  • 使用 Svcutil 生成客户端配置代码,命令示例: svcutil.exe net.tcp://localhost:1111/Design_Time_Addresses/NetTcpBindingWCFServer/Service1/ /out:1.cs ,相关代码可参考: https://github.com/dotnet/samples/tree/main/framework/wcf/Basic/Binding/Net/Tcp/Default/CS

2.客户端编写

(1) 新建项目

选择 Visual C# -> Console Application ,名称为 NetTcpBindingWCFClient

方法同 0x03 中的 2.客户端编写

0x05 通过 IIS 实现 WCF

本节仅以服务端编写作为示例,客户端编写同命令行实现的方法一致

1.服务端编写

(1) 新建项目

选择 Visual C# -> WCF -> WCF Service Library ,名称为 WcfServiceLibrary1

(2) 发布

选中项目, 右键 -> Publish... ,设置 Target location 为 c:\wcfdemo

(3) 在 IIS 管理页面下新建网站

设置以下参数:

  • Site name:wcfdemo
  • Physical path:c:\wcfdemo
  • IP address: All unassigned
  • Port:81

选中网站 wcfdemo,进入 Content View

选中 WcfServiceLibrary1.Service1.svc右键 -> Browse ,得到 URL: http://localhost:81/WcfServiceLibrary2.Service1.svc

(4) 测试

此时开启了 MEX,可选择以下方法进行测试:

0x06 通过服务实现 WCF

本节仅以服务端编写作为示例,客户端编写同命令行实现的方法一致

1.使用 basicHttpBinding 实现服务端

(1) 新建项目

选择 Visual C# -> Console Application ,名称为 WCFService

(2) 新建 Windows Service

选择 Add -> New Item... ,选择 Windows Service ,名称为 Service1.cs

(3) 设置服务信息

选中 Service1.cs右键 -> Add Installer

项目中自动创建 ProjectInstaller.cs 文件,该文件会添加俩个组件 serviceProcessInstaller1 和 serviceInstaller1

选中 serviceProcessInstaller1 组件,查看属性,设置 account 为 LocalSystem

选中 serviceInstaller1 组件,查看属性,设置 ServiceName 为 VulServiceTest1

(4) 编辑 Program.cs

using System;
using System.ServiceModel;
using System.ServiceProcess;
using System.ServiceModel.Description;
namespace WCFService
{
    [ServiceContract]
    public interface IVulnService
    {
        [OperationContract]
        void RunMe(string str);
    }

    public class VulnService : IVulnService
    {
        public void RunMe(string str)
        {
            Console.WriteLine(str);
            System.Diagnostics.Process.Start("CMD.exe", "/c " + str);
        }
    }

    public class WCFService : ServiceBase
    {
        public ServiceHost host = null;

        public WCFService()
        {
            ServiceName = "VulnWCFService";
        }

        public static void Main()
        {
            ServiceBase.Run(new WCFService());
        }

        protected override void OnStart(string[] args)
        {
            if (host != null)
            {
                host.Close();
            }
            try
            {
                Uri baseAddress = new Uri("http://localhost:1112/TestService");
                host = new ServiceHost(typeof(VulnService), baseAddress);
                BasicHttpBinding binding = new BasicHttpBinding();
                host.AddServiceEndpoint(typeof(IVulnService), binding, baseAddress);
                if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
                {
                    ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
                    behavior.HttpGetEnabled = true;
                    host.Description.Behaviors.Add(behavior);
                }
                host.Open();
            }
            catch (CommunicationException ce)
            {
                host.Abort();
            }

        }
        protected override void OnStop()
        {
            if (host != null)
            {
                host.Close();
                host = null;
            }
        }
    }
}

(5) 启动服务

编译生成 WCFService.exe

安装服务:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\installutil WCFService.exe

启动服务:

sc start VulServiceTest1

补充:卸载服务

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\installutil /u WCFService.exe

(6) 测试

此时开启了 MEX,可选择以下方法进行测试:

2.使用 NetTcpBinding 实现服务端

方法同上,区别在于 Program.cs,示例代码如下:

using System;
using System.ServiceModel;
using System.ServiceProcess;
using System.ServiceModel.Description;
namespace WCFService
{
    [ServiceContract]
    public interface IVulnService
    {
        [OperationContract]
        void RunMe(string str);
    }

    public class VulnService : IVulnService
    {
        public void RunMe(string str)
        {
            Console.WriteLine(str);
            System.Diagnostics.Process.Start("CMD.exe", "/c " + str);
        }
    }

    public class WCFService : ServiceBase
    {
        public ServiceHost host = null;

        public WCFService()
        {
            ServiceName = "VulnWCFService";
        }

        public static void Main()
        {
            ServiceBase.Run(new WCFService());
        }

        protected override void OnStart(string[] args)
        {

            if (host != null)
            {
                host.Close();
            }
            try
            {
                host = new ServiceHost(typeof(VulnService));
                host.AddServiceEndpoint(
                        typeof(IVulnService),
                        new NetTcpBinding(),
                        "net.tcp://localhost:1113/TestService");
                if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
                {
                    ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
                    behavior.HttpGetEnabled = true;
                    behavior.HttpGetUrl = new Uri("http://localhost:1114/TestService");
                    host.Description.Behaviors.Add(behavior);
                }
                host.Open();
            }
            catch (CommunicationException ce)
            {
                host.Abort();
            }

        }
        protected override void OnStop()
        {
            if (host != null)
            {
                host.Close();
                host = null;
            }
        }
    }
}

注:服务端设置了 HttpGetUrl: http://localhost:1114/TestService

0x07 小结

本文介绍了在启用元数据发布(MEX) 时 WCF 开发的相关内容,下一篇将要介绍关闭元数据发布(MEX) 时 WCF 开发的相关内容。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

素衣风尘叹

暂无简介

0 文章
0 评论
23 人气
更多

推荐作者

新人笑

文章 0 评论 0

mb_vYjKhcd3

文章 0 评论 0

小高

文章 0 评论 0

来日方长

文章 0 评论 0

哄哄

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文