WCF重写ServiceHost,实现独立配置文件

有时我们需要将WCF的配置文件放在单独的配置文件中,而默认情况下WCF又是在web.config或app.config中去寻找服务配置。如果我们把配置文件放在另一个config文件中,如何让WCF知道呢?

答案就是重写ServiceHost。在重写中告诉WCF配置文件的路径。

  public class MyServiceHost : ServiceHost
  {
        private string ConfigPath =System.AppDomain.CurrentDomain.BaseDirectory+ "MyApp.config";

        public MyServiceHost(Type serviceType, params Uri[] baseAddresses) :
            base(serviceType, baseAddresses)
        {
        }

        protected override void ApplyConfiguration()
        {
            // Check user config invalidation  
            if (!CheckConfigExist(ConfigPath))  
            {  
                // Use default config  
                base.ApplyConfiguration();  
                return;  
            }  
            //base.ApplyConfiguration();  
            // Use user config  
            ExeConfigurationFileMap execfgMap = new ExeConfigurationFileMap();  
            // Set user config FilePath  
            execfgMap.ExeConfigFilename = ConfigPath;  
            // Config info  
            Configuration cfg = ConfigurationManager.OpenMappedExeConfiguration(execfgMap,ConfigurationUserLevel.None);  
            // Gets all service model config sections  
            ServiceModelSectionGroup servicemodelSections = ServiceModelSectionGroup.GetSectionGroup(cfg);  
              
            // Find serivce section matched with the name "this.Description.ServiceType.FullName"   
            if (!ApplySectionInfo(this.Description.ServiceType.FullName,servicemodelSections))  
            {  
                throw new Exception("ConfigApply Error : There is no endpoint existed in your config!! Please check your config file!");  
            }  
            this.ApplyMultiBehaviors(servicemodelSections);  
        }

        /// <summary>
        /// Check config file! 
        /// </summary>
        /// <param name="configpath"></param>
        /// <returns></returns>
        private bool CheckConfigExist(string configpath)
        {
            if (string.IsNullOrEmpty(configpath)) return false;
            if (!File.Exists(configpath)) return false;
            return true;
        }

        /// <summary>
        /// Apply section info
        /// </summary>
        /// <param name="serviceFullName"></param>
        /// <param name="servicemodelSections"></param>
        /// <returns></returns>
        private bool ApplySectionInfo(string serviceFullName, ServiceModelSectionGroup servicemodelSections)
        {
            // Check config sections (!including one section at least!)
            if (servicemodelSections == null) return false;
            // Service name can't be none!
            if (string.IsNullOrEmpty(serviceFullName)) return false;
            bool isElementExist = false;
            foreach (ServiceElement element in servicemodelSections.Services.Services)
            {
                if (element.Name == serviceFullName)
                {
                    // Find successfully & apply section info of config file
                    base.LoadConfigurationSection(element);
                    // Find service element successfully
                    isElementExist = true;
                    break;
                }
            }
            return isElementExist;
        }

        /// <summary>
        /// Add behaviors
        /// </summary>
        /// <param name="servicemodelSections"></param>
        /// <returns></returns>
        private bool ApplyMultiBehaviors(ServiceModelSectionGroup servicemodelSections)
        {
            if (servicemodelSections == null) return false;
            foreach (ServiceBehaviorElement element in servicemodelSections.Behaviors.ServiceBehaviors)
            {
                foreach (BehaviorExtensionElement behavior in element)
                {
                    BehaviorExtensionElement behaviorEx = behavior;
                    object extention = behaviorEx.GetType().InvokeMember("CreateBehavior",
                        BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
                        null,
                        behaviorEx,
                        null);
                    if (extention == null) continue;
                    IServiceBehavior isb = (IServiceBehavior)extention;
                    //if (base.Description.Behaviors.Contains(isb)) break;
                    bool isbehaviorExisted = false;
                    foreach (IServiceBehavior i in base.Description.Behaviors)
                    {
                        if (i.GetType().Name == isb.GetType().Name)
                        {
                            isbehaviorExisted = true;
                            break;
                        }
                    }
                    if (isbehaviorExisted) break;
                    base.Description.Behaviors.Add((IServiceBehavior)extention);
                }
            }
            return true;
        }
    }

像上面那样,我们就把配置文件移到了MyApp.config。如果是控制台程序类的WCF服务就可以像下面那样来启动:

using (MyServiceHost host=new MyServiceHost(typeof(Service1)))
{
     //... do something
     host.Open();
}

而对于宿主是IIS的WCF服务,我们还需要再重写ServiceHostFactory:

public class MyServiceHostFactory :  ServiceHostFactory
{
     protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
     {
          return new MyServiceHost(serviceType, baseAddresses);
     }
}

然后在WCF服务的svc文件中,指定factory属性的值为我们重写的ServiceHostFactory:

<%@ ServiceHost Factory="WcfService1.MyServiceHostFactory"  Language="C#" Debug="true" Service="WcfService1.Service1" CodeBehind="Service1.svc.cs" %>

 

posted @ 2018-08-24 13:27  以德为先  阅读(509)  评论(0编辑  收藏  举报