• 一个ServiceHost寄宿多个服务


    WHY

    Q: "啥? 一个ServiceHost只能寄宿一个ServiceType?? 那我有好多业务逻辑难道要我都塞到一个类里吗?"

    A: 哦,你可以把业务逻辑抽像到多个Interface,然后用一个类来实现

    Q: "那我的项目可能有多个人参与,每个人负责某一个模块,难道要我们N个人去维护一个cs类文件吗?"

    A:你不知道有一个东西叫partial class吗?

    Q:  "shit,你是说每回我要往服务端添加一些业务功能,都得重新编译一遍程序吗?"

    A: 呃...这个...也许你可以...like this

    http://www.cnblogs.com/levinknight/archive/2007/05/25/760176.html

    and this

    http://www.cnblogs.com/jillzhang/archive/2008/11/02/1325081.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后续之旅》系列文章:

    http://www.cnblogs.com/artech/archive/2008/08/26/1276559.html

    public class MyInstanceProvicer : IInstanceProvider
    
    {
    
        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
    
    {
    
        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());
    
    host.Open();

    END

    以上方法,基本实现了一个ServiceHost多个服务的功能,但是还没深入评估,园子里牛人多,希望能指出其中可能存在的陷阱、错误和不足, 拍谢!

  • 相关阅读:
    程序猿也爱学英语(上),有图有真相
    New Year's resolution for 2016
    Got the Best Employee of the year 2015 Star Award
    AngularJs项目文件以及文件夹结构
    完成AngularJS with MVC 5, Web API 2项目
    两则新闻引发的思考
    关于招聘的最新信息
    架构师面试更新版
    2015新加坡总统府
    关于2014年的旅行
  • 原文地址:https://www.cnblogs.com/sweethome/p/one_servicehost_mutil_service.html
Copyright © 2020-2023  润新知