WCF寄宿windows服务二
如果有很多WCF服务需要寄宿,需要额外做一些工作:
总体思路是:先把这些WCF服务的程序集打包,然后利用反射加载各个WCF服务的程序集,按顺序一个一个寄宿。
先来看看我们需要寄宿的WCF服务:
实现步骤:
1、配置文件中打包这些WCF程序集信息。
2、需要自定义配置节点以及实现读取自定义配置节点的方法。
在configSections节点增加配置:
<section name="ValidServices" type="Mdtit.XXX.Mall.Hosting.ValidServicesSection, Mdtit.XXX.Mall.Hosting" />
配置处理类实现如下:
using System; using System.Collections.Generic; using System.Reflection; using System.Configuration; using System.ServiceModel.Configuration; using System.ServiceModel; using System.Xml; using System.Xml.Serialization; using System.IO; using System.ServiceModel.Description; using System.Text; using Mdtit.XXX.Mall.Common; namespace Mdtit.XXX.Mall.Hosting { /// <summary> /// Custom configuration section for valid service setting /// </summary> internal class ValidServicesSection : ConfigurationSection { [ConfigurationProperty("Services")] public ValidServiceCollection ValidServices { get { return this["Services"] as ValidServiceCollection; } } } /// <summary> /// Custom configuration element collection for valid service setting /// </summary> internal class ValidServiceCollection : ConfigurationElementCollection { protected override ConfigurationElement CreateNewElement() { return new ValidService(); } protected override object GetElementKey(ConfigurationElement element) { return ((ValidService)element).Type; } } /// <summary> /// Custom configuration element for valid service setting /// </summary> internal class ValidService : ConfigurationElement { [ConfigurationProperty("Type")] public string Type { get { return (string)this["Type"]; } } } }
3、windows服务的Main函数
static class Program { /// <summary> /// The main entry point for the application. /// </summary> static void Main() { ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new XXXService() }; ServiceBase.Run(ServicesToRun); } }
4、windows服务类:XXXService
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Linq; using System.ServiceProcess; using System.Text; using Mdtit.XXX.Mall.Hosting; using Mdtit.XXX.Mall.Common; using System.ServiceModel; namespace Mdtit.XXX.Mall.Hosting.Service { public partial class XXXService : ServiceBase { /// <summary> /// All avalilable services. /// </summary> static List<ServiceHost> _allHosts = new List<ServiceHost>(); public XXXService() { InitializeComponent(); } protected override void OnStart(string[] args) { try { ServiceManager.StartAllValidServices(); LogHelper.LogInformation("All WCF services started."); } catch (ApplicationException ex) { LogHelper.LogInformation(ex.Message); } } protected override void OnStop() { try { ServiceManager.CloseAllServices(); LogHelper.LogInformation("All WCF services stopped."); } catch (ApplicationException ex) { LogHelper.LogInformation(ex.Message); } } } }
其中,ServiceManager.StartAllValidServices() 和 ServiceManager.CloseAllServices()是用来批量处理WCF服务的。
5、ServiceManager类实现如下:
using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Reflection; using System.ServiceModel; using System.ServiceModel.Description; using System.Text; using Mdtit.XXX.Mall.Common; namespace Mdtit.XXX.Mall.Hosting { /// <summary> /// Helper class to start/stop services /// </summary> internal class ServiceManager { /// <summary> /// Container for all valid services /// </summary> static List<ServiceHost> _AllHosts = new List<ServiceHost>(); /// <summary> /// Start all valid services. /// </summary> public static void StartAllValidServices() { string entryLocation = Assembly.GetEntryAssembly().Location; Configuration conf = ConfigurationManager.OpenExeConfiguration(entryLocation); ValidServicesSection validServiceSettings = ConfigurationManager.GetSection("ValidServices") as ValidServicesSection; if (validServiceSettings != null) { foreach (ValidService validService in validServiceSettings.ValidServices) { string typeToLoad = validService.Type; // Load the assembly dynamic string assemblyName = typeToLoad.Substring(typeToLoad.IndexOf(',') + 1); Assembly.Load(assemblyName); Type svcType = Type.GetType(typeToLoad); if (svcType == null) { string errInfo = string.Format("Invalid Service Type \"{0}\" in configuration file.", typeToLoad); LogHelper.LogError(errInfo); throw new ApplicationException(errInfo); } else { OpenHost(svcType); } } } else { throw new ApplicationException("Application configuration for WCF services not found!"); } } /// <summary> /// Create a host for a specified wcf service; /// </summary> /// <param name="t"></param> private static void OpenHost(Type t) { ServiceHost host = new ServiceHost(t); host.Opened += new EventHandler(hostOpened); host.Closed += new EventHandler(hostClosed); host.Open(); _AllHosts.Add(host); } /// <summary> /// Close all services /// </summary> public static void CloseAllServices() { foreach (ServiceHost host in _AllHosts) { if (host.State != CommunicationState.Closed) { host.Close(); } } } /// <summary> /// Event handler for host opened /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void hostOpened(object sender, EventArgs e) { ServiceDescription svcDesc = ((ServiceHost)sender).Description; string svcName = svcDesc.Name; StringBuilder allUri = new StringBuilder(); foreach (ServiceEndpoint endPoint in svcDesc.Endpoints) { allUri.Append(endPoint.ListenUri.ToString()); } LogHelper.LogInformation(string.Format("Service \"{0}\" started with url: {1}", svcName, allUri.ToString())); } /// <summary> /// Event handler for host closed /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void hostClosed(object sender, EventArgs e) { ServiceDescription svcDesc = ((ServiceHost)sender).Description; string svcName = svcDesc.Name; LogHelper.LogInformation(string.Format("Service \"{0}\" stopped.", svcName)); } } }
6、开始寄宿
以管理员身份运行我们前面写好的windows服务程序:
结果: