有时我们需要将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" %>