wCF REST 注意点
服务注册路径问题
RouteTable.Routes.Add(new ServiceRoute("Ipc/", hostFactory, typeof(ServiceImp)));
RouteTable.Routes.Add(new ServiceRoute("Ipc/LoginService/", hostFactory, typeof(LoginServiceImp)));
这样注册的顺序会导致Ipc/LoginService/xxx 发布的终结点找不到,把后一句的移到前面,又正常了
RouteTable.Routes.Add(new ServiceRoute("Ipc/", hostFactory, typeof(ServiceImp)));
RouteTable.Routes.Add(new ServiceRoute("Ipc2/LoginService/", hostFactory, typeof(LoginServiceImp)));
路径前缀不同的也可以正常访问到
使用WebInvoke时只支持一个参数
默认的web方式实例管理是采用PerCall的,这样服务类针对每次调用都会New一次
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections.Concurrent; using System.Diagnostics; namespace DynamicIP.Server.IIS { using DynamicIP.Interface; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Activation; using System.Web; [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] [ServiceBehavior(IncludeExceptionDetailInFaults = true,InstanceContextMode = InstanceContextMode.PerCall)] public partial class ServiceImp : IService { public ServiceImp() { Debug.WriteLine(this.GetHashCode()); } #region IDynamicIpService 成员 public string RegIp(string clientNo) { var properties = OperationContext.Current.IncomingMessageProperties; var endPoint = properties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty; var ip= endPoint.Address; var model = new ClientIpModel() { AddTime = DateTime.Now, ClientNo = clientNo, IP = ip, RecId = -1, UpdateTime = DateTime.Now }; ClientIpDB.Instance.Save(model); Console.WriteLine(string.Format("ClientNo:{0},IP:{1}",clientNo,ip)); return DateTime.Now + "-->" + ip; } public List<ClientIpModel> Query(string clientNo, int top, string inbTime, string ineTime) { DateTime bt, et; DateTime? bTime = null, eTime = null; if (DateTime.TryParse(inbTime, out bt)) { bTime = bt; } if (DateTime.TryParse(ineTime, out et)) { eTime = et; } if (top <= 0) top = 100; return ClientIpDB.Instance.Query(clientNo, top, bTime, eTime); } public string Help() { StringBuilder sb = new StringBuilder(); sb.Append("格式:/Query?clientNo={clientNo}&top={top}&btime={btime}&etime={etime}"); return sb.ToString(); } #endregion #region IService 成员 public int Add(int a, int b) { return a + b; } #endregion } #region 客户域名库 public class ClientIpDB { private ClientIpDB(){} private static Lazy<ClientIpDB> _LazyClientIpDB = new Lazy<ClientIpDB>(() => new ClientIpDB(), true); public static ClientIpDB Instance { get { return _LazyClientIpDB.Value; } } private static volatile int MaxRecId=0; public int GetMaxId() { return ++MaxRecId; } private static int MaxElmCount = 11000; private static int MoveCount = 1000; private ConcurrentQueue<ClientIpModel> _Queue = new ConcurrentQueue<ClientIpModel>(); /// <summary> /// 获取对应客户号的域名 /// </summary> /// <param name="clientId"></param> /// <returns></returns> public string GetDomainBy(string clientNo) { return "www.geely.com"; } public void Save(ClientIpModel model) { var it= Update(model); if (it == null) { model.RecId = GetMaxId(); Add(model); } } public ClientIpModel Update(ClientIpModel model) { var it= _Queue.Where(ent => ent.ClientNo == model.ClientNo).FirstOrDefault(); if (it != null) { it.IP = model.IP; it.UpdateTime = DateTime.Now; it.Domain = model.Domain; } return it; } public void Add(ClientIpModel model) { _Queue.Enqueue(model); if (_Queue.Count > MaxElmCount ) { for (int i = 0; i < MoveCount; i++) { ClientIpModel outIt=null; _Queue.TryDequeue(out outIt); } } } public List<ClientIpModel> Query(string clientNo,int top, DateTime? btime, DateTime? etime) { var q=_Queue.AsQueryable(); if(!string.IsNullOrWhiteSpace(clientNo)) { q = q.Where(ent => ent.ClientNo == clientNo); } if (btime.HasValue) { q = q.Where(ent => ent.UpdateTime >= btime); } if (etime.HasValue) { q = q.Where(ent => ent.UpdateTime <= etime); } return q.Take(top).ToList(); } } #endregion }
客户端调用时需要指定个定WebHttpBehavior
//#define Release using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DynamicIP.Console { using DynamicIP.Interface; using System.ServiceModel; using System.Runtime.InteropServices; using System.ServiceModel.Description; using System.ServiceModel.Channels; using System.ServiceModel.Dispatcher; using System.Web; public class MyClientMsgInspector : IClientMessageInspector, IEndpointBehavior { #region IClientMessageInspector 成员 private string _AuthUserId = string.Empty; public void AfterReceiveReply(ref Message reply, object correlationState) { if (reply.Properties.ContainsKey("httpResponse")) { HttpResponseMessageProperty httpResponse = reply.Properties["httpResponse"] as HttpResponseMessageProperty; if (httpResponse != null) { string cookie = httpResponse.Headers.Get("Set-Cookie"); if (!string.IsNullOrWhiteSpace(cookie)) { _AuthUserId = cookie; } //if (cookie != null) _cookie = cookie; } } } public object BeforeSendRequest(ref Message request, IClientChannel channel) { if (_AuthUserId != string.Empty && request.Properties.ContainsKey("httpRequest")) { HttpRequestMessageProperty httpRequest = request.Properties["httpRequest"] as HttpRequestMessageProperty; if (httpRequest != null) { httpRequest.Headers["Cookie"] = _AuthUserId; } } return null; } #endregion #region IEndpointBehavior 成员 public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { return; } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { clientRuntime.MessageInspectors.Add(this); } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { return; } public void Validate(ServiceEndpoint endpoint) { return; } #endregion } class Program { #region 平台调用 & console 窗口隐藏 [DllImport("user32.dll")] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll")] static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); public static void SetConsoleWindowVisibility(bool visible, string title) { // below is Brandon's code //Sometimes System.Windows.Forms.Application.ExecutablePath works for the caption depending on the system you are running under. IntPtr hWnd = FindWindow(null, title); if (hWnd != IntPtr.Zero) { if (!visible) //Hide the window ShowWindow(hWnd, 0); // 0 = SW_HIDE else //Show window again ShowWindow(hWnd, 1); //1 = SW_SHOWNORMA } } #endregion [STAThread()] static void Main(string[] args) { #if Release var title = Guid.NewGuid().ToString("N"); Console.Title = title; SetConsoleWindowVisibility(false, title); #endif //try //{ var binding = new WebHttpBinding(); binding.AllowCookies = true; var clientMsgInspector = new MyClientMsgInspector(); var address1 = new EndpointAddress("http://localhost:13773/Ipc/loginService/"); var sep1 = new ServiceEndpoint(ContractDescription.GetContract(typeof(ILogin)), binding, address1); sep1.Behaviors.Add(new WebHttpBehavior()); using (ChannelFactory<ILogin> channelFactory = new ChannelFactory<ILogin>(sep1)) { channelFactory.Endpoint.Behaviors.Add(clientMsgInspector); var proxy = channelFactory.CreateChannel(); var clientNo = System.Configuration.ConfigurationManager.AppSettings["ClientNo"]; proxy.Login(new LoginRequest() { Username = "xx", Password = "xx" }); } System.Console.ReadKey(); var address = new EndpointAddress("http://localhost:13773/Ipc/ipService"); var sep = new ServiceEndpoint(ContractDescription.GetContract(typeof(IService)), binding, address); sep.Behaviors.Add(new WebHttpBehavior()); using (ChannelFactory<IService> channelFactory = new ChannelFactory<IService>(sep)) { channelFactory.Endpoint.Behaviors.Add(clientMsgInspector); var proxy = channelFactory.CreateChannel(); //var scope = new OperationContextScope(((IClientChannel)proxy)); //var curId = Guid.NewGuid(); // MessageHeader<Guid> mhg = new MessageHeader<Guid>(curId); // MessageHeader untyped = mhg.GetUntypedHeader("token", "ns"); // OperationContext.Current.OutgoingMessageHeaders.Add(untyped); var clientNo = System.Configuration.ConfigurationManager.AppSettings["ClientNo"]; proxy.RegIp(clientNo); var t= proxy.Query("", 100, "", ""); var proxy2 = channelFactory.CreateChannel(); clientNo = System.Configuration.ConfigurationManager.AppSettings["ClientNo"]; proxy2.RegIp("9999"); var t2 = proxy2.Add(5, 16); } //} //catch (Exception) //{ // //eat err //} System.Console.ReadKey(); } } }
cookie问题
var binding = new WebHttpBinding();
binding.AllowCookies = true; 设置的cookie http头不能正确提交
而当allowCookies=false,客户端可以提交cookie http头