一个serviceHost多个wcf服务,为什么宿主为console可以,而windows服务就不行呢?
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.ServiceModel; 5 using System.ServiceModel.Activation; 6 using System.ServiceModel.Web; 7 using System.Text; 8 9 namespace WcfRestServiceLibrary.Service 10 { 11 [ServiceContract(Namespace = "WcfRestServiceLibrary.Service")] 12 public interface IMicroblogService 13 { 14 [OperationContract] 15 [WebGet(UriTemplate = "")] 16 List<Microblog> GetCollection(); 17 18 [OperationContract] 19 [WebInvoke(UriTemplate = "", Method = "POST", RequestFormat = WebMessageFormat.Json)] 20 Microblog Create(Microblog microblog); 21 22 [OperationContract] 23 [WebGet(UriTemplate = "{id}",RequestFormat = WebMessageFormat.Xml,ResponseFormat=WebMessageFormat.Json)] 24 Microblog Get(string id); 25 26 [OperationContract] 27 [WebInvoke(UriTemplate = "{id}", Method = "DELETE")] 28 void Delete(string id); 29 30 [OperationContract] 31 [WebInvoke(Method = "PUT")] 32 void Modify( Microblog microblog); 33 } 34 }
1 using System; 2 using System.Runtime.Serialization; 3 4 namespace WcfRestServiceLibrary.Service 5 { 6 [DataContract(Namespace = "WcfRestServiceLibrary.Service")] 7 public class Microblog 8 { 9 [DataMember] 10 public int Id { get; set; } 11 [DataMember] 12 public string Content { get; set; } 13 [DataMember] 14 public DateTime PublishTime { get; set; } 15 } 16 17 18 }
1 using System; 2 using System.Collections.Concurrent; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Net; 6 using System.ServiceModel; 7 using System.ServiceModel.Activation; 8 using System.ServiceModel.Web; 9 using System.Threading; 10 11 namespace WcfRestServiceLibrary.Service 12 { 13 [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] 14 [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] 15 public class MicroblogService:IMicroblogService 16 { 17 private static int _currentId; 18 private static IList<Microblog> _microblogs = new List<Microblog> 19 { 20 new Microblog() {Id=5,Content="Hello,haha",PublishTime =DateTime .Now}, 21 new Microblog() {Id=6,Content="test,test",PublishTime =Convert.ToDateTime("2014/03/25")} 22 }; 23 24 public List<Microblog> GetCollection() 25 { 26 return _microblogs.ToList(); 27 } 28 29 public Microblog Create(Microblog microblog) 30 { 31 microblog.Id = Interlocked.Increment(ref _currentId); 32 _microblogs.Add(microblog); 33 return microblog; 34 } 35 36 public Microblog Get(string id) 37 { 38 Microblog microblog = _microblogs.FirstOrDefault(e => e.Id == int.Parse(id)); 39 if(null==microblog) 40 { 41 WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.NotFound; 42 } 43 return microblog; 44 } 45 46 public void Delete(string id) 47 { 48 Microblog microblog = Get(id); 49 if(null!=microblog) 50 { 51 _microblogs.Remove(microblog); 52 } 53 54 } 55 56 public void Modify(Microblog microblog) 57 { 58 Delete(microblog.Id.ToString()); 59 _microblogs.Add(microblog); 60 } 61 62 } 63 }
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Runtime.Serialization; 6 using System.ServiceModel.Web; 7 using System.ServiceModel; 8 9 namespace Artech.WcfServices.Service 10 { 11 [ServiceContract] 12 public interface IEmployees 13 { 14 [WebGet(UriTemplate = "all")] 15 IEnumerable<Employee> GetAll(); 16 17 [WebGet(UriTemplate = "{id}")] 18 Employee Get(string id); 19 20 [WebInvoke(UriTemplate = "/", Method = "POST")] 21 void Create(Employee employee); 22 23 [WebInvoke(UriTemplate = "/", Method = "PUT")] 24 void Update(Employee employee); 25 26 [WebInvoke(UriTemplate = "{id}", Method = "DELETE")] 27 void Delete(string id); 28 } 29 30 [DataContract(Namespace = "Artech.WcfServices.Service")] 31 public class Employee 32 { 33 [DataMember] 34 public string Id { get; set; } 35 [DataMember] 36 public string Name { get; set; } 37 [DataMember] 38 public string Department { get; set; } 39 [DataMember] 40 public string Grade { get; set; } 41 42 public override string ToString() 43 { 44 return string.Format("ID: {0,-5}姓名: {1, -5}级别: {2, -4} 部门: {3}", Id, Name, Grade, Department); 45 } 46 } 47 }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel.Web; using System.Net; namespace Artech.WcfServices.Service { public class EmployeesService : IEmployees { private static IList<Employee> employees = new List<Employee> { new Employee{ Id = "001", Name="张三", Department="开发部", Grade = "G7"}, new Employee{ Id = "002", Name="李四", Department="人事部", Grade = "G6"} }; public Employee Get(string id) { Employee employee = employees.FirstOrDefault(e => e.Id == id); if (null == employee) { WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.NotFound; } return employee; } public void Create(Employee employee) { employees.Add(employee); } public void Update(Employee employee) { this.Delete(employee.Id); employees.Add(employee); } public void Delete(string id) { Employee employee = this.Get(id); if (null != employee) { employees.Remove(employee); } } public IEnumerable<Employee> GetAll() { return employees; } } }
以下是控制台程序,wcf宿主在console:
1 using System; 2 using System.Collections.Generic; 3 using System.Configuration; 4 using System.Linq; 5 using System.Reflection; 6 using System.ServiceModel; 7 using System.ServiceModel.Configuration; 8 9 namespace ConsoleApplication1 10 { 11 class Program 12 { 13 static List<ServiceHost> listHost = null; 14 static ServiceHost host = null; 15 static void Main(string[] args) 16 { 17 //Uri baseAddress = new Uri("http://localhost:8083/MicroblogService"); 18 //ServiceHost _host = new ServiceHost(typeof(MicroblogService), baseAddress); 19 20 ////WebServiceHost _host = new WebServiceHost(typeof(MicroblogService),baseAddress); 21 //using (_host) 22 //{ 23 // ServiceEndpoint endPoint = _host.AddServiceEndpoint(typeof(IMicroblogService), new WebHttpBinding(), baseAddress); 24 // WebHttpBehavior httpBehavior = new WebHttpBehavior(); 25 // httpBehavior.HelpEnabled = true; 26 // endPoint.Behaviors.Add(httpBehavior); 27 // _host.Opened += delegate 28 // { 29 // Console.WriteLine("Console Hosted successfully."); 30 // }; 31 // _host.Open(); 32 // Console.ReadLine(); 33 //} 34 //WebServiceHost _host = new WebServiceHost(typeof(MicroblogService)); 35 //_host.Opened += delegate 36 //{ 37 // Console.WriteLine("Console Hosted successfully."); 38 //}; 39 //_host.Open(); 40 //Console.ReadLine(); 41 42 OpenService(); 43 Console.ReadLine(); 44 } 45 46 public static void OpenService() 47 { 48 try 49 { 50 listHost = new List<ServiceHost>(); 51 Configuration conf = ConfigurationManager.OpenExeConfiguration(Assembly.GetEntryAssembly().Location); 52 53 if (conf != null) 54 { 55 ServiceModelSectionGroup svcmod = (ServiceModelSectionGroup)conf.GetSectionGroup("system.serviceModel"); 56 foreach (ServiceElement el in svcmod.Services.Services) 57 { 58 59 string klassName = el.Name.Substring(el.Name.LastIndexOf('.') + 1); 60 Assembly asmb = Assembly.LoadFrom(klassName + ".dll"); 61 Type svcType = asmb.GetType(el.Name); 62 63 if (svcType == null) 64 { 65 continue; 66 } 67 host = new ServiceHost(svcType); 68 69 host.Open(); 70 if (!listHost.Contains(host)) 71 { 72 listHost.Add(host); 73 } 74 } 75 } 76 } 77 catch (Exception ex) 78 { 79 Console.WriteLine(ex.Message ); 80 } 81 } 82 } 83 }
app.config:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <system.serviceModel> 4 <services> 5 <!-- This section is optional with the new configuration model 6 introduced in .NET Framework 4. --> 7 <service name="WcfRestServiceLibrary.Service.MicroblogService" behaviorConfiguration="MicroblogServiceBehavior"> 8 <host> 9 <baseAddresses> 10 <add baseAddress="http://127.0.0.1:8034/MicroblogService"/> 11 </baseAddresses> 12 </host> 13 <endpoint address="http://127.0.0.1:8034/MicroblogService" 14 binding="webHttpBinding" 15 contract="WcfRestServiceLibrary.Service.IMicroblogService" behaviorConfiguration="web"/> 16 </service> 17 18 <service name="Artech.WcfServices.Service.EmployeesService" behaviorConfiguration="EmployeesServiceBehavior"> 19 <host> 20 <baseAddresses> 21 <add baseAddress="http://127.0.0.1:3724/EmployeesService"/> 22 </baseAddresses> 23 </host> 24 <endpoint address="http://127.0.0.1:3724/EmployeesService" 25 binding="webHttpBinding" 26 contract="Artech.WcfServices.Service.IEmployees" behaviorConfiguration="web"/> 27 </service> 28 29 </services> 30 31 <behaviors> 32 <serviceBehaviors> 33 <behavior name="MicroblogServiceBehavior" > 34 <serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:8034/MicroblogService/MetaData"/> 35 </behavior> 36 <behavior name="EmployeesServiceBehavior" > 37 <serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:3724/EmployeesService/MetaData"/> 38 </behavior> 39 </serviceBehaviors> 40 <endpointBehaviors> 41 <behavior name="web"> 42 <webHttp helpEnabled="true" /> 43 </behavior> 44 </endpointBehaviors> 45 </behaviors> 46 47 <!--<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />--> 48 </system.serviceModel> 49 </configuration>
启动console程序,运行测试:
以上足以证明,控制台程序一启动,两个wcf service都可正常使用了。
但为何host变成windows service就得不到这样的结果呢?
using System; using System.Collections.Generic; using System.Linq; using System.ServiceProcess; using System.Text; namespace WindowsServiceDemo { static class Program { /// <summary> /// 应用程序的主入口点。 /// </summary> static void Main() { ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new WindowsServiceDemo1() }; ServiceBase.Run(ServicesToRun); //WindowsServiceDemo1 wsd = new WindowsServiceDemo1(); //wsd.OpenService(); } } }
1 using System; 2 using System.Collections.Generic; 3 using System.Configuration; 4 using System.Reflection; 5 using System.ServiceModel; 6 using System.ServiceModel.Configuration; 7 using System.ServiceModel.Description; 8 using System.ServiceModel.Web; 9 using System.ServiceProcess; 10 using WcfRestServiceLibrary.Service; 11 using log4net; 12 13 14 namespace WindowsServiceDemo 15 { 16 public partial class WindowsServiceDemo1 : ServiceBase 17 { 18 /// <summary> 19 /// 要启动的服务 20 /// </summary> 21 List<ServiceHost> listHost = null; 22 ServiceHost host = null; 23 private log4net.ILog logger = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 24 public WindowsServiceDemo1() 25 { 26 InitializeComponent(); 27 } 28 29 protected override void OnStart(string[] args) 30 { 31 OpenServices(); 32 } 33 34 public void OpenServices() 35 { 36 try 37 { 38 listHost = new List<ServiceHost>(); 39 Configuration conf = ConfigurationManager.OpenExeConfiguration(Assembly.GetEntryAssembly().Location); 40 41 if (conf != null) 42 { 43 ServiceModelSectionGroup svcmod = (ServiceModelSectionGroup)conf.GetSectionGroup("system.serviceModel"); 44 foreach (ServiceElement el in svcmod.Services.Services) 45 { 46 47 string klassName = el.Name.Substring(el.Name.LastIndexOf('.') + 1); 48 Assembly asmb = Assembly.LoadFrom(klassName + ".dll"); 49 Type svcType = asmb.GetType(el.Name); 50 51 if (svcType == null) 52 { 53 continue; 54 } 55 host = new ServiceHost(svcType); 56 57 host.Open(); 58 if (!listHost.Contains(host)) 59 { 60 listHost.Add(host); 61 } 62 } 63 } 64 } 65 catch (Exception ex) 66 { 67 logger.Error(ex.Message); 68 } 69 } 70 protected override void OnStop() 71 { 72 CloseServices(); 73 } 74 75 76 void CloseServices() 77 { 78 try 79 { 80 81 if (listHost != null && listHost.Count > 0) 82 { 83 84 foreach (ServiceHost host in listHost) 85 { 86 if (host != null) 87 { 88 host.Close(); 89 } 90 } 91 92 } 93 } 94 catch (Exception ex) 95 { 96 97 } 98 } 99 } 100 }
哪位大侠帮帮忙?在此先谢过!
通过加入logger日志,发现并解决了问题。
app.config文件内容:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 4 <configSections> 5 <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net-net-1.0" /> 6 </configSections> 7 8 9 <log4net> 10 <root> 11 <level value="ALL" /> 12 <appender-ref ref="LogFileAppender" /> 13 </root> 14 15 <appender name="LogFileAppender" type="log4net.Appender.FileAppender" > 16 <param name="File" value="Log\log-file.txt" /> 17 <param name="AppendToFile" value="true" /> 18 <layout type="log4net.Layout.PatternLayout"> 19 <param name="ConversionPattern" value="记录时间:%d 线程 ID:[%t] 日志级别:%-5p 出错类:%logger property:[%property{NDC}] 错误描述:%m%n" /> 20 </layout> 21 </appender> 22 </log4net> 23 <system.serviceModel> 24 <services> 25 <!-- This section is optional with the new configuration model 26 introduced in .NET Framework 4. --> 27 <service name="WcfRestServiceLibrary.Service.MicroblogService" behaviorConfiguration="MicroblogServiceBehavior"> 28 <host> 29 <baseAddresses> 30 <add baseAddress="http://127.0.0.1:8033/MicroblogService"/> 31 </baseAddresses> 32 </host> 33 <endpoint address="http://127.0.0.1:8033/MicroblogService" 34 binding="webHttpBinding" 35 contract="WcfRestServiceLibrary.Service.IMicroblogService" behaviorConfiguration="web"/> 36 </service> 37 <service name="Artech.WcfServices.Service.EmployeesService" behaviorConfiguration="EmployeesServiceBehavior"> 38 <host> 39 <baseAddresses> 40 <add baseAddress="http://127.0.0.1:3723/EmployeesService"/> 41 </baseAddresses> 42 </host> 43 <endpoint address="http://127.0.0.1:3723/EmployeesService" 44 binding="webHttpBinding" 45 contract="Artech.WcfServices.Service.IEmployees" behaviorConfiguration="web"/> 46 </service> 47 </services> 48 49 <behaviors> 50 <serviceBehaviors> 51 <behavior name="MicroblogServiceBehavior" > 52 <serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:8033/MicroblogService/MetaData"/> 53 </behavior> 54 <behavior name="EmployeesServiceBehavior" > 55 <serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:3723/EmployeesService/MetaData"/> 56 </behavior> 57 </serviceBehaviors> 58 <endpointBehaviors> 59 <behavior name="web"> 60 <webHttp helpEnabled="true" /> 61 </behavior> 62 </endpointBehaviors> 63 </behaviors> 64 65 <!--<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />--> 66 </system.serviceModel> 67 68 </configuration>
windows服务程序入口:
1 using System.ServiceProcess; 2 3 4 namespace WindowsServiceDemo 5 { 6 static class Program 7 { 8 /// <summary> 9 /// 应用程序的主入口点。 10 /// </summary> 11 static void Main() 12 { 13 ServiceBase[] ServicesToRun; 14 ServicesToRun = new ServiceBase[] 15 { 16 new WindowsServiceDemo1() 17 }; 18 ServiceBase.Run(ServicesToRun); 19 } 20 } 21 }
服务启动需要运行的WindowsServiceDemo1类文件:
注意:WindowsServiceDemo1类命名空间外加了log4net的配置属性。
1 using System; 2 using System.Collections.Generic; 3 using System.Configuration; 4 using System.Reflection; 5 using System.ServiceModel; 6 using System.ServiceModel.Configuration; 7 using System.ServiceProcess; 8 using log4net; 9 10 [assembly: log4net.Config.DOMConfigurator(ConfigFile = "app.config", Watch = true)] 11 namespace WindowsServiceDemo 12 { 13 public partial class WindowsServiceDemo1 : ServiceBase 14 { 15 /// <summary> 16 /// 要启动的服务 17 /// </summary> 18 List<ServiceHost> listHost = null; 19 ServiceHost host = null; 20 private log4net.ILog logger = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 21 22 public WindowsServiceDemo1() 23 { 24 InitializeComponent(); 25 } 26 27 protected override void OnStart(string[] args) 28 { 29 OpenServices(); 30 } 31 32 33 public void OpenServices() 34 { 35 try 36 { 37 listHost = new List<ServiceHost>(); 38 Configuration conf = ConfigurationManager.OpenExeConfiguration(Assembly.GetEntryAssembly().Location); 39 40 logger.Info("开始启动服务......"); 41 if (conf != null) 42 { 43 ServiceModelSectionGroup svcmod = (ServiceModelSectionGroup)conf.GetSectionGroup("system.serviceModel"); 44 foreach (ServiceElement el in svcmod.Services.Services) 45 { 46 logger.Debug("..."+el.Name ); 47 string klassName = el.Name.Substring(el.Name.LastIndexOf('.') + 1); 48 logger.Debug("..1111." + conf.FilePath.Substring(0, conf.FilePath.LastIndexOf('\\')+1) + klassName + ".dll"); 49 Assembly asmb = Assembly.LoadFrom(conf.FilePath.Substring(0, conf.FilePath.LastIndexOf('\\')+1) + klassName + ".dll"); 50 logger.Debug("..222..." ); 51 Type svcType = asmb.GetType(el.Name); 52 logger.Debug("..333..." + svcType); 53 if (svcType == null) 54 { 55 continue; 56 } 57 host = new ServiceHost(svcType); 58 logger.Info(host.Description.Endpoints[0]); 59 60 logger.Info(el.Name + ":服务已经启动了"); 61 host.Open(); 62 logger.Debug("..444..." ); 63 if (!listHost.Contains(host)) 64 { 65 logger.Debug("..555..."); 66 listHost.Add(host); 67 logger.Debug("..6666..."); 68 } 69 } 70 } 71 else 72 { 73 logger.Warn("没有找到服务对应的配置信息"); 74 } 75 } 76 catch (Exception ex) 77 { 78 logger.Error(ex.Message); 79 } 80 } 81 protected override void OnStop() 82 { 83 CloseServices(); 84 } 85 86 void CloseServices() 87 { 88 try 89 { 90 91 if (listHost != null && listHost.Count > 0) 92 { 93 94 foreach (ServiceHost host in listHost) 95 { 96 if (host != null) 97 { 98 host.Close(); 99 } 100 } 101 102 } 103 } 104 catch (Exception ex) 105 { 106 107 } 108 } 109 } 110 }
另外ProjectInstaller.cs上两个(serviceInstaller1和serviceProcessInstaller1)组件设置下属性,就不多说了。
然后installutil注册安装服务,启动时修改属性,为本地系统帐户,确保是管理员身份启动,否则无权限访问配置文件中所配置的两个服务的地址
启动服务后,查看运行结果:
想上传整个解决方案源码,却不知道怎么上传
太长了,可以如下试试:
1)测试OpenServices方法,确保在控制台里能够执行;
2)确保window服务已经启动;
3)跟踪日志,看是否有错误,并在函数里面加上logger.Error(your message)来跟踪;
谢谢,加上logger日志,找出原因了!
@Erica Chen: 谢谢,一次拿那么多钱给我,我泪流满面啊,哈哈!!!
Configuration conf = ConfigurationManager.OpenExeConfiguration(Assembly.GetEntryAssembly().Location);
这段代码放在 Windows 服务中运行有问题。
真的好佩服啊