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

目标:创建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上部署的效果图如下图:

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

 

 

 

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

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

 

 

 

 

当需要新增一个服务时,只需要新增服务契约接口和服务实现,并在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上部署的效果图如下图:

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

 

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

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

 

 

 

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

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

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

 

 

 

 

 

 

上一篇:WCF - WCF基本概念和简单WCF服务端创建 (一)


下一篇:conda