WCF中使用 ServiceHostFactory 扩展宿主(实现无配置文件)

10 篇文章 0 订阅

目标:创建wcf服务无配置文件,可快速扩展

 

 

部署环境: 该方式只能在IIS中部署

 

核心是使用ServiceHostFactory类,继承改类,并重写CreateServiceHost方法,可以参考微软官方文档:https://docs.microsoft.com/zh-cn/dotnet/framework/wcf/extending/extending-hosting-using-servicehostfactory

 

步骤:

1  新建类库项目,名称为WcfExtend,并为该项目添加System.ServiceModel.dll和System.ServiceModel.Activation.dll引用

 

2  新增测试服务

    2.1  新建契约接口,名称为IService1,代码如下:

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


namespace WcfExtend
{
    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        string HelloWorld();
    }
}


2.2  新增类,名称为Service1,并继承契约接口IService1,代码如下:

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

namespace WcfExtend {
    public class Service1 : IService1
    {
        public string HelloWorld()
        {
            return "Hello Word,zxy";
        }
    }
}

 

 

3   编写 ServiceHostFactory 扩展宿主,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Description;
using System.Text;
using System.Threading.Tasks;

namespace WcfExtend
{
    //添加System.ServiceModel.dll和System.ServiceModel.Activation.dll引用
    public class WcfHostServiceFactory:ServiceHostFactory
    {

        //实现契约接口对应的服务名称,第一个参数是契约名称,第二个是实现契约对应的服务类对应的Type
        Dictionary<string, Type> ServiceNameDict = new Dictionary<string, Type>();



        private string ServiceHostTypeNameClassName = "System.ServiceModel.ServiceHost, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
        
        
        
        
        
        /// <summary>
        /// 重写CreateServiceHost
        /// </summary>
        /// <param name="serviceType"></param>
        /// <param name="baseAddresses"></param>
        /// <returns></returns>
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {

            ServiceNameDict.Add("WcfExtend.IService1",typeof(Service1));
           
            //ServiceNameDict.Add("", "");
            Type ServiceImpType = null;
            ServiceNameDict.TryGetValue(serviceType.FullName, out ServiceImpType);
            ServiceHost host=CreateServiceHost(serviceType, baseAddresses, ServiceImpType);
            return host;
           
        }

        private ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses,Type ServiceType)
        {
            

           
            
            Type serviceImplType = ServiceType;

            Type serviceHostType = Type.GetType(ServiceHostTypeNameClassName, true);

            //动态创建ServiceHost
            ServiceHost serviceHost = Activator.CreateInstance(serviceHostType, new object[] { serviceImplType, baseAddresses }) as ServiceHost;


            //添加终结点
            InitEndPoint(serviceHost, serviceType);

            //添加Behavior
            ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
            behavior.HttpGetEnabled = true;
            serviceHost.Description.Behaviors.Add(behavior);




            return serviceHost;
        }


        /// <summary>
        /// 初始化终结点
        /// </summary>
        /// <param name="host"></param>
        /// <param name="serviceType"></param>
        private void InitEndPoint(ServiceHost host,Type serviceType)
        {
            BasicHttpBinding binding = new BasicHttpBinding();
            host.AddServiceEndpoint(serviceType, binding,binding.Name);
        }
    }
}

 

4  生成项目,并把生成的Dll部署到IIS上,步骤如下:

  4.1   新增svc文件,名称带后缀为Service1.svc,内容如下:

<% @ServiceHost Factory="WcfExtend.WcfHostServiceFactory"  Service="WcfExtend.IService1" %>

Service为    命名空间+契约接口名称 

4.2 把项目生成的dll复制到IIS的bin目录(没有就新增)

 

4.3  新增web.config配置文件,内容如下:

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

    <system.webServer>
        <directoryBrowse enabled="true" />
    </system.webServer>


 

</configuration>

 

最终在IIS上部署的效果图如下图:

 

 

 

在浏览器中浏览的效果如下图:

 

 

 

 

当需要新增一个服务时,只需要新增服务契约接口和服务实现,并在WcfHostServiceFactory类中增加一行代码 ServiceNameDict.Add("WcfExtend.契约接口名称", typeof(实现的服务类))  即可

如:

新增契约接口,名称为IService2,代码如下:

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

namespace WcfExtend
{
    [ServiceContract]
    interface IService2
    {
        [OperationContract]
        string GetMsg();
    }
}

 

新增服务类,名称为 Service2,并继承契约接口IService2,代码如下:

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

namespace WcfExtend
{
    public class Service2 : IService2
    {
        public string GetMsg()
        {
            return "Service2";
        }
    }
}

 

在前面的WcfHostServiceFactory类中新增一行代码ServiceNameDict.Add("WcfExtend.IService2", typeof(Service2)),完整代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Description;
using System.Text;
using System.Threading.Tasks;

namespace WcfExtend
{
    //添加System.ServiceModel.dll和System.ServiceModel.Activation.dll引用
    public class WcfHostServiceFactory:ServiceHostFactory
    {

        //实现契约接口对应的服务名称,第一个参数是契约名称,第二个是实现契约对应的服务类对应的Type
        Dictionary<string, Type> ServiceNameDict = new Dictionary<string, Type>();



        private string ServiceHostTypeNameClassName = "System.ServiceModel.ServiceHost, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
        
        
        
        
        
        /// <summary>
        /// 重写CreateServiceHost
        /// </summary>
        /// <param name="serviceType"></param>
        /// <param name="baseAddresses"></param>
        /// <returns></returns>
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {

            ServiceNameDict.Add("WcfExtend.IService1",typeof(Service1));
            ServiceNameDict.Add("WcfExtend.IService2", typeof(Service2));
            //ServiceNameDict.Add("", "");
            Type ServiceImpType = null;
            ServiceNameDict.TryGetValue(serviceType.FullName, out ServiceImpType);
            ServiceHost host=CreateServiceHost(serviceType, baseAddresses, ServiceImpType);
            return host;
           
        }

        private ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses,Type ServiceType)
        {
            

           
            
            Type serviceImplType = ServiceType;

            Type serviceHostType = Type.GetType(ServiceHostTypeNameClassName, true);

            //动态创建ServiceHost
            ServiceHost serviceHost = Activator.CreateInstance(serviceHostType, new object[] { serviceImplType, baseAddresses }) as ServiceHost;


            //添加终结点
            InitEndPoint(serviceHost, serviceType);

            //添加Behavior
            ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
            behavior.HttpGetEnabled = true;
            serviceHost.Description.Behaviors.Add(behavior);




            return serviceHost;
        }


        /// <summary>
        /// 初始化终结点
        /// </summary>
        /// <param name="host"></param>
        /// <param name="serviceType"></param>
        private void InitEndPoint(ServiceHost host,Type serviceType)
        {
            BasicHttpBinding binding = new BasicHttpBinding();
            host.AddServiceEndpoint(serviceType, binding,binding.Name);
        }
    }
}

 

生成项目,并把生成的dll以覆盖的形式放到iis的bin目录下,再新增svc文件,名称为Service2.svc,里面的内容如下:

<% @ServiceHost Factory="WcfExtend.WcfHostServiceFactory"  Service="WcfExtend.IService2" %>

 

 

这样,新增的服务就完成了

 

最终iis上部署的效果图如下图:

 

在浏览器中效果图如下图:

 

 

 

拓展(我们公司就是这么干的):

1  可以把契约定义单独放到单独类库中,服务实现放到单独的类库,这样就可以通过反射获取到服务实现的Type类型

2   获取到ServiceHost实例后,可以根据需要动态配置(如绑定、Behavior等)(当然这些动态的配置信息可以保存在数据库中)

 

 

 

 

 

 

完整的服务端及客户端调用程序,在win7+ vs2015环境运行通过. 一、说明 1、创建winfrom应用程序;(或者是控制台项目) 2、在项目添加一个WCF服务,并实现服务; 3、在需要启动WebService服务的地方启动该服务即可; 二、代码如下: 1、新建一个WCF服务——定义服务接口    [ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]     public interface ICalculator     {         [OperationContract]         double Add(double n1, double n2);     } 2、新建一个WCF服务——实现服务 public class CalculatorService : ICalculator     {         public double Add(double n1, double n2)         {             return n1 + n2;         }     } 3、添加完WcF服务后会在应用程序配置文件有入下节点                             <!--TestServer.ICalculator服务定义的接口,根据自己定义进行修改-->                                                                   <baseAddresses> <!--这个是要发布的服务地址,可以进行修改-->                                   </baseAddresses>                   4、在要启动服务的地方启动服务监听   public frmMain() { InitializeComponent(); } private void frmMain_Load(object sender, EventArgs e) { try { //打开服务创建监听,并开始监听消息 ServiceHost serviceHost = new ServiceHost(typeof(Service1));//需要using System.ServiceModel; serviceHost.Open(); label1.Text = "服务启动正常"; } catch (Exception ex) { label1.Text = ex.Message; } } 5、下面可以在客户端通过上面的服务地址”http://xxx.xxx.xxx.xx:8733/test/Service1/“对服务进行调用 到这步就实现在控制台实现webService的发布。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zxy2847225301

测试使用

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值