一个ServiceHost寄宿多个服务
2010-11-16 16:24
357 查看
WHY
Q: "啥? 一个ServiceHost只能寄宿一个ServiceType?? 那我有好多业务逻辑难道要我都塞到一个类里吗?"A: 哦,你可以把业务逻辑抽像到多个Interface,然后用一个类来实现
Q: "那我的项目可能有多个人参与,每个人负责某一个模块,难道要我们N个人去维护一个cs类文件吗?"
A:你不知道有一个东西叫partial class吗?
Q: "shit,你是说每回我要往服务端添加一些业务功能,都得重新编译一遍程序吗?"
A: 呃...这个...也许你可以...like this
/article/4815617.html
and this
/article/4598954.html
Q: “oh no, 这样我的系统还叫系统吗? 针对每个service一遍又一遍的权限验证和安全配置?”
A: >.<
WANT
1, 以插件的方式开发wcf服务端,业务模块以独立dll的方式注册到宿主里2,业务模块的添加删除是动态的,服务端主程序无需重新编译
3,无须为每个业务模快servicetype单独做配置,注册一个业务模块只需在host里添加一个endpoint和操作契约
...
HOW
默认情况下,servicehost在收到客户端调用时,可以判断出调用的契约interface, 然后用构造函数传入的servicetype创建实例并转型为对应的interface进行方法调用而为了实现一个servicehost能对应多个服务, 我们需要改变他的实例创建的行为,WCF里可以用InstanceProvider来实现这一机制.
具体InstanceProvider用法及wcf服务端的消息dispatch机制可以参考园子里的大牛Artech的《WCF后续之旅》系列文章:
/article/1308553.html
public class MyInstanceProvicer : IInstanceProvider{[/code]
private string contractType;
public MyInstanceProvicer(string contractType)
{
this.contractType = contractType;
}
public object GetInstance(InstanceContext instanceContext,
System.ServiceModel.Channels.Message message)
{
/*在注册业务模块的时候,可以把实现业务模块的assembly,业务模块的type name,
* 业务模块所实现的契约接口记录到一张表里,然后在这里通过契约找到对应的业
* 务模块信息,实例化出类实例,返回给servicehost*/
switch (contractType)
{
case "IFoobar":
return new WcfService1.Service1();
break;
case "ISayHello":
return new WcfService2.Service1();
break;
default:
return null;
break;
}
return null;
}
public object GetInstance(InstanceContext instanceContext)
{
return GetInstance(instanceContext, null);
}
public void ReleaseInstance(InstanceContext instanceContext,
object instance)
{
Console.WriteLine("releaseInstance::" + instance.ToString());
}
}
public class InstanceProviderBehavior : IServiceBehavior
{
void IServiceBehavior.AddBindingParameters(
ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase,
System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints,
System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
void IServiceBehavior.ApplyDispatchBehavior(
ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher channelDispatcher
in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher endpointDispatcher
in channelDispatcher.Endpoints)
{
endpointDispatcher.DispatchRuntime.InstanceProvider =
new MyInstanceProvicer(endpointDispatcher.ContractName);
}
}
}
void IServiceBehavior.Validate(ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase)
{
}
}
通过ServiceBehavior把InstanceProvider应用到servicehost上
host.Description.Behaviors.Add(new InstanceProviderBehavior());
通过以上的方法,事实上我们已经拦截了servicehost对servicetype的实例化过程,可是我们还有一个问题得解决,这个servicehost本身应该怎么实例化呢?构造函数里的servicetype传什么??
由于servicehost在初始化的时候,会检查传入构造函数的serivcetype是否实现了在endpoint里注册的所有契约interface,只要有一个interface没实现就会抛出异常.
这可怎么办?我可不知道最后我的serivcehost会host多少个契约,这个servicetype是没办法在开发期间实现的.
幸好,dotnet提供了反射和动态创建类型的功能,在实例化servicehost的时候,把所有注册的业务模块契约接口列出来,并动态创建一个实现了这些接口的类型就可以了.
参考:
通过Emit实现动态类生成
http://www.souzz.net/html/edu/net/net11/3478.html
public class TypeCreator{[/code]
public TypeCreator()
{
}
public Type build()
{
AppDomain currentAppDomain = AppDomain.CurrentDomain;
AssemblyName assyName = new AssemblyName();
assyName.Name = "DynamicAssemblyForServiceType";
AssemblyBuilder assyBuilder =
currentAppDomain.DefineDynamicAssembly(assyName,
AssemblyBuilderAccess.Run);
ModuleBuilder modBuilder =
assyBuilder.DefineDynamicModule("DynamicModuleForServiceType");
String newTypeName = "DynamicServiceType";
TypeAttributes newTypeAttribute =
TypeAttributes.Class | TypeAttributes.Public;
//在这里把注册的业务模块契约列出来
Type[] newTypeInterfaces = new Type[] {
typeof(WcfService1.IFoobar), typeof(WcfService2.ISayHello) };
TypeBuilder typeBuilder = modBuilder.DefineType(newTypeName,
newTypeAttribute, null, newTypeInterfaces);
//实现接口
foreach (Type baseInterface in newTypeInterfaces)
{
MethodInfo[] targetMethods = baseInterface.GetMethods();
foreach (MethodInfo targetMethod in targetMethods)
{
if (targetMethod.IsVirtual)
{
ParameterInfo[] paramInfo = targetMethod.GetParameters();
Type[] paramType = new Type[paramInfo.Length];
for (int i = 0; i < paramInfo.Length; i++)
paramType[i] = paramInfo[i].ParameterType;
MethodBuilder methodBuilder = typeBuilder.DefineMethod(
targetMethod.Name,
MethodAttributes.Public | MethodAttributes.Virtual,
targetMethod.ReturnType, paramType);
ILGenerator ilGen = methodBuilder.GetILGenerator();
ilGen.Emit(OpCodes.Ret); //该方法具体应该实现什么功能不重要.
}
}
}
return (typeBuilder.CreateType());
}
}
现在有了servicetype,可以创建servicehost的实例了
ServiceHost host = new ServiceHost(new TypeCreator().build());host.Description.Behaviors.Add(new InstanceProviderBehavior());
[/code]
host.Open();
END
以上方法,基本实现了一个ServiceHost多个服务的功能,但是还没深入评估,园子里牛人多,希望能指出其中可能存在的陷阱、错误和不足, 拍谢!相关文章推荐
- Wcf 基础教程 服务寄宿之编码实现 ServiceHost
- 重温WCF之构建一个简单的WCF(一)(2)通过Windows Service寄宿服务和WCF中实现操作重载
- WCF学习(2) ServiceHost寄宿多个服务
- C#制作Windows service服务系列一:制作一个可安装、可启动、可停止、可卸载的Windows service(downmoon原创)
- 关于”System.ServiceModel.Activation.WebServiceHostFactory“与"<webHttp/>"以及RestFul/启用了Ajax的WCF服务
- Wcf Ria Services学习笔记(二):创建一个简单WCF RIA Service服务
- C#制作Windows service服务系列一:制作一个可安装、可启动、可停止、可卸载的Windows service
- 在服务 ObtainData 实现的协定列表中找不到协定名称 "IMetadataExchange"。将 ServiceMetadataBehavior 添加到配置文件或直接添加到 ServiceHost,以启用对该协定的支持。
- [推荐]将软件作为一个服务Software as a Service SaaS
- 一个Windows服务如何host多个wcf服务?
- C#制作Windows service服务系列一:制作一个可安装、可启动、可停止、可卸载的Windows service
- C#制作Windows service服务系列二:演示一个定期执行的windows服务及调试(windows service)(转载)
- WCF中 改名后 无法找到 ServiceHost 指令中作为服务属性值提供的类型“WCFDemo.Service1”。
- C#制作Windows service服务系列二--演示一个定期执行的windows服务及调试
- SpringBootService,一个基于spring boot搭建的SOA服务框架
- C#制作Windows service服务系列一:制作一个可安装、可启动、可停止、可卸载的Windows service
- 如何增加一个系统服务service
- C#制作Windows service服务系列二--演示一个定期执行的windows服务及调试
- World Wide Web Publishing Service 服务成功发送一个 停止 控件
- [转]WCF一个Host实现多契约服务