Important Update: The originally presented code only works if the service is defined in the same assembly which hosts the service (because the name="" attribute in <service> may not contain the assembly name of the service). See at the end of the article for a slightly different version which works in all cases --- but which involves adding a second config file.
As WCF has reached RC1 stage, I find myself cleaning up a few bits of older WCF code. While playing around with it, I always found myself having to start more and more ServiceHosts for different configurations. The following snippet iterates over all <service> entries in configuration/system.serviceModel and opens a ServiceHost for each of them.
Update: Added code to close all services.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Configuration;
using System.ServiceModel.Configuration;
using System.ServiceModel;
public class ServiceHostGroup
{
static List<ServiceHost> _hosts = new List<ServiceHost>();
private static void OpenHost(Type t)
{
ServiceHost hst = new ServiceHost(t);
hst.Open();
_hosts.Add(hst);
}
public static void StartAllConfiguredServices()
{
Configuration conf =
ConfigurationManager.OpenExeConfiguration(Assembly.GetEntryAssembly().Location);
ServiceModelSectionGroup svcmod =
(ServiceModelSectionGroup)conf.GetSectionGroup("system.serviceModel");
foreach (ServiceElement el in svcmod.Services.Services)
{
Type svcType = Type.GetType(el.Name);
if (svcType == null)
throw new Exception("Invalid Service Type " + el.Name + " in configuration file.");
OpenHost(svcType);
}
}
public static void CloseAllServices()
{
foreach (ServiceHost hst in _hosts)
{
hst.Close();
}
}
}
As mentioned above, I have in the meantime learned (after long and hard fighting against the "this service has no non-metadata endpoints"-exception), that the name="" attribute in <service> must not contain an assembly name. I guess I have been too used to Remoting configuration files after all ;-). To still get dynamic service configuration without code changes, I've added a second configuration file called services.xml and changed the code for ServiceHostGroup to the following:
Services.XML:
<configuredServices>
<service type="ServiceImplementation.ArticleService, ServiceImplementation" />
</configuredServices>
ServiceHostBase.cs:
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;
public class ServiceHostGroup
{
static List<ServiceHost> _hosts = new List<ServiceHost>();
private static void OpenHost(Type t)
{
ServiceHost hst = new ServiceHost(t);
Type ty = hst.Description.ServiceType;
hst.Open();
_hosts.Add(hst);
}
public static void StartAllConfiguredServices()
{
ConfiguredServices services = ConfiguredServices.LoadFromFile("services.xml");
foreach (ConfiguredService svc in services.Services)
{
Type svcType = Type.GetType(svc.Type);
if (svcType == null) throw new Exception("Invalid Service Type " + svc.Type + " in configuration file.");
OpenHost(svcType);
}
}
public static void CloseAllServices()
{
foreach (ServiceHost hst in _hosts)
{
hst.Close();
}
}
}
[XmlRoot("configuredServices")]
public class ConfiguredServices
{
public static ConfiguredServices LoadFromFile(string filename)
{
if (!File.Exists(filename)) return new ConfiguredServices();
XmlSerializer ser = new XmlSerializer(typeof(ConfiguredServices));
using (FileStream fs = File.OpenRead(filename))
{
return (ConfiguredServices) ser.Deserialize(fs);
}
}
[XmlElement("service", typeof(ConfiguredService))]
public List<ConfiguredService> Services = new List<ConfiguredService>();
}
public class ConfiguredService
{
[XmlAttribute("type")]
public string Type;
}
=========================================================
原文地址http://blogs.thinktecture.com/ingo/archive/2006/09/05/414686.aspx
评论部分
Nicholas Paldino [.NET/C# MVP]
In this case, I would rely on ServiceHost as it exists today. Other than that, a CloseAllService() would be as simple as
public static void CloseAllServices()
{
foreach (ServiceHost hst in _hosts)
{
hst.Close();
}
}
Cheers,
-Ingo
Ingo Rammer
Christopher Steen
As WCF has reached RC1 stage, I find myself cleaning up a few bits of older WCF code. While playing around with it, I always found myself having to start more and more ServiceHosts for different configurations. The following snippet iterates over all <service> entries in configuration/system.serviceModel and opens a ServiceHost for each of them.
Update: Added code to close all services.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Configuration;
using System.ServiceModel.Configuration;
using System.ServiceModel;
public class ServiceHostGroup
{
static List<ServiceHost> _hosts = new List<ServiceHost>();
private static void OpenHost(Type t)
{
ServiceHost hst = new ServiceHost(t);
hst.Open();
_hosts.Add(hst);
}
public static void StartAllConfiguredServices()
{
Configuration conf =
ConfigurationManager.OpenExeConfiguration(Assembly.GetEntryAssembly().Location);
ServiceModelSectionGroup svcmod =
(ServiceModelSectionGroup)conf.GetSectionGroup("system.serviceModel");
foreach (ServiceElement el in svcmod.Services.Services)
{
Type svcType = Type.GetType(el.Name);
if (svcType == null)
throw new Exception("Invalid Service Type " + el.Name + " in configuration file.");
OpenHost(svcType);
}
}
public static void CloseAllServices()
{
foreach (ServiceHost hst in _hosts)
{
hst.Close();
}
}
}
As mentioned above, I have in the meantime learned (after long and hard fighting against the "this service has no non-metadata endpoints"-exception), that the name="" attribute in <service> must not contain an assembly name. I guess I have been too used to Remoting configuration files after all ;-). To still get dynamic service configuration without code changes, I've added a second configuration file called services.xml and changed the code for ServiceHostGroup to the following:
Services.XML:
<configuredServices>
<service type="ServiceImplementation.ArticleService, ServiceImplementation" />
</configuredServices>
ServiceHostBase.cs:
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;
public class ServiceHostGroup
{
static List<ServiceHost> _hosts = new List<ServiceHost>();
private static void OpenHost(Type t)
{
ServiceHost hst = new ServiceHost(t);
Type ty = hst.Description.ServiceType;
hst.Open();
_hosts.Add(hst);
}
public static void StartAllConfiguredServices()
{
ConfiguredServices services = ConfiguredServices.LoadFromFile("services.xml");
foreach (ConfiguredService svc in services.Services)
{
Type svcType = Type.GetType(svc.Type);
if (svcType == null) throw new Exception("Invalid Service Type " + svc.Type + " in configuration file.");
OpenHost(svcType);
}
}
public static void CloseAllServices()
{
foreach (ServiceHost hst in _hosts)
{
hst.Close();
}
}
}
[XmlRoot("configuredServices")]
public class ConfiguredServices
{
public static ConfiguredServices LoadFromFile(string filename)
{
if (!File.Exists(filename)) return new ConfiguredServices();
XmlSerializer ser = new XmlSerializer(typeof(ConfiguredServices));
using (FileStream fs = File.OpenRead(filename))
{
return (ConfiguredServices) ser.Deserialize(fs);
}
}
[XmlElement("service", typeof(ConfiguredService))]
public List<ConfiguredService> Services = new List<ConfiguredService>();
}
public class ConfiguredService
{
[XmlAttribute("type")]
public string Type;
}
=========================================================
原文地址http://blogs.thinktecture.com/ingo/archive/2006/09/05/414686.aspx
评论部分
Start ServiceHosts for all configured Services @ Tuesday, September 05, 2006 4:24 PM
While services will more than likely have the same lifetime as an app-domain, they are in no way required to live for the life of the app-domain that they are in. You should expose a way to shut down a particular service as well.Nicholas Paldino [.NET/C# MVP]
# re: Start ServiceHosts for all configured Services @ Tuesday, September 05, 2006 4:31 PM
Absolutely. It just appears to me that, whenever you want to start/stop services on demand, you will quite likely have a need for more fine grained startup/shutdown behavior (only starting/stopping a subset of them depending on your runtime conditions).In this case, I would rely on ServiceHost as it exists today. Other than that, a CloseAllService() would be as simple as
public static void CloseAllServices()
{
foreach (ServiceHost hst in _hosts)
{
hst.Close();
}
}
Cheers,
-Ingo
Ingo Rammer
# Link Listing - September 5, 2006 @ Wednesday, September 06, 2006 1:54 PM
Atlas is weighing on me [Via: James Avery ] Hex Dump Utility [Via: tomasr@mvps.org (Tomas Restrepo)...Christopher Steen