我遇到了一个问题,我可以从一个网络服务的登录电话中检索两个Cookie,但这两个Cookie都会从对其他网络服务的请求中删除。
一点背景:我有一个Windows服务(.NET 4.5)需要将数据发送到另一个公司的Web服务接口。它们的界面由几个不同的独立Web服务组成。要连接,我必须从他们的一个服务调用web方法登录;我将其称为服务A.登录方法返回由DateTime标记组成的Long值以及两个cookie:会话cookie和授权cookie。每个请求都必须包含两个cookie。
如果我调用服务A中的任何方法,请求中都包含两个cookie。使用Fiddler我已经能够验证这一点。但是,如果我尝试在服务B中调用方法,则两个cookie在发出之前都会从请求调用中被删除。
以下是我目前使用的类和代码:
CookieBehavior类
public sealed class CookieBehavior : IContractBehavior, IEndpointBehavior, IClientMessageInspector
{
#region Private fields
public CookieContainer cookieContainer = new CookieContainer();
#endregion
#region Public constructors
public CookieBehavior()
: this(true)
{
}
public CookieBehavior(Boolean shared)
{
this.Shared = shared;
}
#endregion
#region Public properties
public Boolean Shared
{
get;
private set;
}
#endregion
#region Private methods
private void getCookies(HttpResponseMessageProperty prop, CookieContainer cookieContainer)
{
if (prop != null)
{
String header = prop.Headers[HttpResponseHeader.SetCookie];
if (header != null)
{
String[] cookies = header.Split(',');
var cc = new CookieCollection();
foreach (string cookie in cookies)
{
if (cookie.Contains(";"))
{
cc.Add(new Cookie(cookie.Substring(0, cookie.IndexOf("=")),
cookie.Substring(cookie.IndexOf("=") + 1, cookie.IndexOf(";") - (cookie.IndexOf("=") + 1))));
}
else
{
cc.Add(new Cookie(cookie.Substring(0, cookie.IndexOf("=")), cookie.Substring(cookie.IndexOf("=") + 1)));
}
}
cookieContainer.Add(new Uri(@"http://tempuri.org"), cc);
}
}
}
private void setCookies(HttpRequestMessageProperty prop, CookieContainer cookieContainer)
{
if (prop != null)
{
prop.Headers.Add(HttpRequestHeader.Cookie, cookieContainer.GetCookieHeader(new Uri(@"http://tempuri.org")));
}
}
#endregion
#region IClientMessageInspector Members
void IClientMessageInspector.AfterReceiveReply(ref Message reply, Object correlationState)
{
if (((this.Shared == true) ? CookieContext.Current.cookieContainer : this.cookieContainer).Count == 0)
{
HttpResponseMessageProperty prop = reply.Properties[HttpResponseMessageProperty.Name.ToString()] as HttpResponseMessageProperty;
this.getCookies(prop, (this.Shared == true) ? CookieContext.Current.cookieContainer : this.cookieContainer);
}
}
Object IClientMessageInspector.BeforeSendRequest(ref Message request, IClientChannel channel)
{
HttpRequestMessageProperty prop = null;
if (request.Properties.ContainsKey(HttpRequestMessageProperty.Name.ToString()))
prop = request.Properties[HttpRequestMessageProperty.Name.ToString()] as HttpRequestMessageProperty;
else
prop = new HttpRequestMessageProperty();
this.setCookies(prop, (this.Shared == true) ? CookieContext.Current.cookieContainer : this.cookieContainer);
return (null);
}
#endregion
#region IEndpointBehavior Members
void IEndpointBehavior.AddBindingParameters(ServiceEndpoint serviceEndpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime behavior)
{
behavior.MessageInspectors.Add(this);
}
void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint, EndpointDispatcher endpointDispatcher)
{
}
void IEndpointBehavior.Validate(ServiceEndpoint serviceEndpoint)
{
}
#endregion
#region IContractBehavior Members
void IContractBehavior.AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
void IContractBehavior.ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
endpoint.Behaviors.Add(this);
}
void IContractBehavior.ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
}
void IContractBehavior.Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
}
#endregion
}
CookieContext类
public class CookieContext : IDisposable
{
#region Internal fields
internal CookieContainer cookieContainer = new CookieContainer();
#endregion
#region Private static fields
[ThreadStatic]
private static CookieContext current = null;
#endregion
#region Public static constructor
public CookieContext()
{
current = this;
}
#endregion
#region Public static properties
public static CookieContext Current
{
get
{
return (current);
}
}
#endregion
#region IDisposable Members
void IDisposable.Dispose()
{
this.cookieContainer.SetCookies(new Uri(@"http://tempuri.org"), String.Empty);
this.cookieContainer = null;
current = null;
}
#endregion
}
我的代码
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
ServicePointManager.ServerCertificateValidationCallback = ((sender, certificate, chain, sslPolicyErrors) => true);
using (var cookieCtx = new CookieContext())
{
ServiceA.ServiceASoapClient serviceA_req = new ServiceA.ServiceASoapClient();
ServiceB.ServiceBSoapClient serviceB_req = new ServiceB.ServiceBSoapClient();
var cookieBhr = new CookieBehavior(true);
serviceA_req.Endpoint.EndpointBehaviors.Add(cookieBhr);
serviceB_req.Endpoint.EndpointBehaviors.Add(cookieBhr);
long? loginTicks = serviceA_req.InterfaceLogin();
if (loginTicks.HasValue)
{
// Get/Set data for request call
serviceB_resp = serviceB_req.SendData(fooBar);
}
}
调试我的应用程序表明,两个cookie头都是从请求中正确设置的,但在服务B请求之前它们被剥离了。
为什么两个cookie都会从第二个请求中删除?