wcf Rest 服务宿主在windows服务及客户端访问
首先写好服务,代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Runtime.Serialization; 4 using System.ServiceModel.Web; 5 using System.ServiceModel; 6 7 8 namespace Artech.WcfServices.Service 9 { 10 [ServiceContract(Namespace = "Artech.WcfServices.Service")] 11 public interface IEmployees 12 { 13 [OperationContract] 14 [WebGet(UriTemplate = "all", ResponseFormat = WebMessageFormat.Json)] 15 IEnumerable<Employee> GetAll(); 16 17 [OperationContract] 18 [WebGet(UriTemplate = "{id}")] 19 Employee Get(string id); 20 21 [OperationContract] 22 [WebInvoke(UriTemplate = "/", Method = "POST", RequestFormat=WebMessageFormat.Json)] 23 void Create(Employee employee); 24 25 [OperationContract] 26 [WebInvoke(UriTemplate = "/Add", Method = "POST", RequestFormat = WebMessageFormat.Json)] 27 void Add(string employee); 28 29 [OperationContract] 30 [WebInvoke(UriTemplate = "/", Method = "PUT")] 31 void Update(Employee employee); 32 33 [OperationContract] 34 [WebInvoke(UriTemplate = "{id}", Method = "DELETE")] 35 void Delete(string id); 36 } 37 38 [DataContract(Namespace = "Artech.WcfServices.Service")] 39 public class Employee 40 { 41 [DataMember] 42 public int Id { get; set; } 43 [DataMember] 44 public string Name { get; set; } 45 [DataMember] 46 public string Department { get; set; } 47 [DataMember] 48 public string Grade { get; set; } 49 [DataMember] 50 public bool IsHire { get; set; } 51 [DataMember] 52 public DateTime EntryDate { get; set; } 53 } 54 }
服务实现类:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 using System.Linq; 5 using System.Reflection; 6 using System.Runtime.Serialization.Json; 7 using System.Text; 8 using System.ServiceModel.Web; 9 using System.Net; 10 11 namespace Artech.WcfServices.Service 12 { 13 public class EmployeesService : IEmployees 14 { 15 private log4net.ILog logger = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 16 private static List<Employee> employees = new List<Employee> 17 { 18 new Employee{ Id = 1 ,Name="张三", Department="开发部", Grade = "G7",EntryDate =Convert.ToDateTime("2013/07/08"),IsHire =true}, 19 new Employee{ Id = 2, Name="李四", Department="人事部", Grade = "G6",EntryDate= Convert.ToDateTime("2014/03/11"),IsHire =false}, 20 new Employee{ Id = 3, Name="王五", Department="销售部", Grade = "G8",EntryDate =Convert.ToDateTime("2010/12/10"),IsHire =true} 21 }; 22 public Employee Get(string id) 23 { 24 Employee employee = employees.FirstOrDefault(e => e.Id == int.Parse(id)); 25 if (null == employee) 26 { 27 WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.NotFound; 28 } 29 return employee; 30 } 31 public void Create(Employee employee) 32 { 33 employees.Add(employee); 34 } 35 private void W(string msg) 36 { 37 var sr=new StreamWriter("C:/1.txt",true); 38 sr.Write(msg); 39 sr.Write("\r\n"); 40 sr.Close(); 41 sr.Dispose(); 42 } 43 public void Add(string employee) 44 { 45 46 W(employee); 47 try 48 { 49 Employee emp = Deserialize<Employee>(employee); 50 51 employees.Add(emp); 52 } 53 catch (Exception ex) 54 { 55 W(ex.ToString()); 56 } 57 58 } 59 60 public void Update(Employee employee) 61 { 62 // var emp = JsonConvert.DeserializeObject<Employee>(employee); 63 this.Delete(employee.Id.ToString()); 64 employees.Add(employee); 65 } 66 public void Delete(string id) 67 { 68 Employee employee = this.Get(id); 69 if (null != employee) 70 { 71 employees.Remove(employee); 72 } 73 } 74 public IEnumerable<Employee> GetAll() 75 { 76 return employees; 77 } 78 public static T Deserialize<T>(string json) 79 { 80 var jsondata = Encoding.UTF8.GetBytes(json); 81 var obj = Activator.CreateInstance<T>(); 82 using (var ms = new MemoryStream(jsondata)) 83 { 84 var serializer = new DataContractJsonSerializer(obj.GetType()); 85 return (T)serializer.ReadObject(ms); 86 } 87 } 88 89 } 90 }
还可以定义更多的服务,如MicroblogService、UserService等,和EmployeeService一样,代码略过。
然后让它们寄宿在windows service应用程序上,如下:
新建一个项目,名称为WindowsServiceDemo,写app.config配置文件:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 <service name="WcfRestServiceLibrary.Service.MicroblogService" behaviorConfiguration="MicroblogServiceBehavior"> 26 <host> 27 <baseAddresses> 28 <add baseAddress="http://localhost:8033/MicroblogService"/> 29 </baseAddresses> 30 </host> 31 <endpoint address="http://localhost:8033/MicroblogService" 32 binding ="webHttpBinding" 33 contract="WcfRestServiceLibrary.Service.IMicroblogService" behaviorConfiguration="web"/> 34 </service> 35 <service name="Artech.WcfServices.Service.EmployeesService" behaviorConfiguration="EmployeesServiceBehavior"> 36 <host> 37 <baseAddresses> 38 <add baseAddress="http://localhost:3723/EmployeesService"/> 39 </baseAddresses> 40 </host> 41 <endpoint address="http://localhost:3723/EmployeesService" 42 binding ="webHttpBinding" 43 contract="Artech.WcfServices.Service.IEmployees" behaviorConfiguration="web"/> 44 </service> 45 <service name="WcfRestServiceLibrary.UserService.UserService" behaviorConfiguration="UserServiceBehavior"> 46 <host> 47 <baseAddresses> 48 <add baseAddress="http://localhost:7033/UserService"/> 49 </baseAddresses> 50 </host> 51 <endpoint address="http://localhost:7033/UserService" 52 binding ="webHttpBinding" 53 contract="WcfRestServiceLibrary.UserService.IUserService" behaviorConfiguration="web"/> 54 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> 55 </service> 56 <service name="wcfServiceLib.Service1" behaviorConfiguration="Service1Behavior"> 57 <host> 58 <baseAddresses> 59 <add baseAddress="http://localhost:6033/Service1"/> 60 </baseAddresses> 61 </host> 62 <endpoint address="http://localhost:6033/Service1" 63 binding ="webHttpBinding" 64 contract="wcfServiceLib.IService1" behaviorConfiguration="web"/> 65 </service> 66 </services> 67 68 <behaviors> 69 <serviceBehaviors> 70 <behavior name="MicroblogServiceBehavior" > 71 <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:8033/MicroblogService/MetaData"/> 72 </behavior> 73 <behavior name="EmployeesServiceBehavior" > 74 <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:3723/EmployeesService/MetaData"/> 75 </behavior> 76 <behavior name="UserServiceBehavior" > 77 <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:7033/UserService/MetaData"/> 78 </behavior> 79 <behavior name="Service1Behavior" > 80 <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:6033/Service1/MetaData"/> 81 </behavior> 82 </serviceBehaviors> 83 <endpointBehaviors> 84 <behavior name="web"> 85 <webHttp helpEnabled="true" /> 86 </behavior> 87 </endpointBehaviors> 88 </behaviors> 89 </system.serviceModel> 90 91 <system.web> 92 <globalization requestEncoding ="gb2312" responseEncoding ="gb2312"/> 93 </system.web> 94 </configuration>
WindowsServiceDemo1.cs代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
Program.cs文件代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
加入组件serviceInstaller1和serviceProcessInstaller1分别设置好服务名称、显示名称、及account等
使用命令安装服务:
installutil D:\WcfRestServiceDemo1\WcfRestServiceDemo1\WindowsServiceDemo\bin\Debug\WindowsServiceDemo1.exe
确保程序和服务都是管理员身份,启动服务。代码中已加入日志,在IE浏览器中输入“http://localhost:3723/EmployeesService”,若显示不出,则服务有问题,可查看日志文件找原因。
服务启动OK后,写控制台客户端代码:
在解决方案中新增一控制台项目为ClientConsoleDynamicProject,app.config文件不用配置,直接写program.cs文件,如下代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Text; 3 using Microsoft.Http; 4 using Newtonsoft.Json.Linq; 5 using System.Runtime.Serialization.Json; 6 7 namespace ClientConsoleDynamicProject 8 { 9 class Program 10 { 11 static dynamic GetModel(string id,string name,string department,string grade,string isHire,string entryDate) 12 { 13 dynamic model=new JObject(); 14 model.Id = id; 15 model.Name = name; 16 model.Department = department ; 17 model.Grade =grade ; 18 model.IsHire = isHire; 19 model.EntryDate = ConvertDateStringToJsonDate(entryDate); 20 return model; 21 } 22 private static string ConvertDateStringToJsonDate(string dateTime) 23 { 24 string result = string.Empty; 25 DateTime dt = DateTime.Parse(dateTime); 26 dt = dt.ToUniversalTime(); 27 TimeSpan ts = dt - DateTime.Parse("1970-1-1"); 28 result = string.Format("/Date({0}+0800)/", ts.TotalMilliseconds); 29 return result; 30 } 31 32 static void Main(string[] args) 33 { 34 var client = new HttpClient(); 35 var strUrl = "http://localhost:3723/EmployeesService/{0}"; 36 strUrl = string.Format(strUrl, "2"); 37 var response = client.Get(strUrl); 38 response.EnsureStatusIsSuccessful(); 39 var json = response.Content.ReadAsString(); 40 Console.WriteLine(json); 41 42 //create 43 string jsonModel = GetModel("5","Jimmy as 张奇","文学部","G3","true","2012/09/05 12:23:08").ToString(); 44 Console.WriteLine(jsonModel ); 45 var data = Encoding.UTF8.GetBytes(jsonModel); 46 strUrl = "http://localhost:3723/EmployeesService/"; 47 HttpContent content = HttpContent.Create( data,"application/json"); 48 response = client.Post(strUrl, content); 49 response.EnsureStatusIsSuccessful(); 50 51 //get all 52 strUrl = "http://localhost:3723/EmployeesService/all"; 53 response = client.Get(strUrl); 54 var xml = response.Content.ReadAsString(); 55 Console.WriteLine("=============新增数据后,get all============="); 56 Console.WriteLine(xml); 57 #region update,delete 58 ////update 59 //strUrl = "http://localhost:3723/EmployeesService/"; 60 //dynamic model = new JObject(); 61 //model.Id = 2; 62 //model.Name = "牛牛"; 63 //model.Department = "开发部"; 64 //model.Grade = "G2"; 65 //model.EntryDate = ConvertDateStringToJsonDate("2000/01/01"); 66 //jsonModel = model.ToString(); 67 //data = Encoding.UTF8.GetBytes(jsonModel); 68 //content = HttpContent.Create(data, "application/json"); 69 //response = client.Put(strUrl, content); 70 //response.EnsureStatusIsSuccessful(); 71 72 ////delete 73 //strUrl = "http://localhost:3723/EmployeesService/{0}"; 74 //strUrl = string.Format(strUrl, "7"); 75 //response = client.Delete(strUrl); 76 //response.EnsureStatusIsSuccessful(); 77 #endregion 78 //add 79 //jsonModel = GetModel("6", "小猫咪", "事业部", "G8", "true", "2013/07/02 22:08:52").ToString(); 80 jsonModel = "\"{\\\"Department\\\":\\\"业务部\\\",\\\"EntryDate\\\":\\\"\\/Date(1372774132000+0800)\\/\\\",\\\"Grade\\\":\\\"G5\\\",\\\"Id\\\":10,\\\"IsHire\\\":true,\\\"Name\\\":\\\"张大伟\\\"}\""; 81 Console.WriteLine(jsonModel); 82 data = Encoding.UTF8.GetBytes(jsonModel); 83 strUrl = "http://localhost:3723/EmployeesService/Add"; 84 content = HttpContent.Create(data, "application/json"); 85 response = client.Post(strUrl, content); 86 //response = client.Delete(strUrl+jsonModel); 87 response.EnsureStatusIsSuccessful(); 88 89 //get all 90 strUrl = "http://localhost:3723/EmployeesService/all"; 91 response = client.Get(strUrl); 92 json = response.Content.ReadAsString(); 93 Console.WriteLine("=============get all============="); 94 Console.WriteLine(json); 95 Console.Read(); 96 } 97 } 98 }
执行客户端程序,OK。
需要注意的:
1.json格式中日期转换的问题,代码中已处理。若不处理,默认时使用的ISO8601的日期格式,而它需要“\/Date(1234656000000)\/”形式的日期格式,否则总报“BadRequest (400)”错误。
2.客户端调用服务中Add方法时,参数是string,在post时字符串需作处理。比如:“ss”字符串,传入时需写成“\"ss\"”,也就是说引号必须传入才是它能接受的。否则也总报“BadRequest (400)”错误。