目标:创建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等)(当然这些动态的配置信息可以保存在数据库中)