向WCF服务中的Response添加多个cookie的问题

时间:2011-02-28 16:03:17

标签: wcf setcookie

我通过在响应标头中添加“Set-Cookie”属性,设法在WCF服务传出响应中添加多个cookie。它工作得很好,只有当有一个cookie而不是多个cookie时,cookie才可用于所有后续请求。请参考我的下面的实现。我通过实现IDispatchMessageInspector接口将cookie添加到响应头中,以便在响应中更新任何挂起的cookie时在所有WCF服务方法调用中添加cookie。

响应标头和请求标头中输出的Cookie示例

1 Cookie: foo = testcookie1; path = / - >在所有后续请求调用中都可用 2个或更多cookie: foo = testcookie1; path = /;,foo2 = testcookie2; path = /;,foo3 = testcookie3; path = /; - > - >只有所有后续请求调用中可用的第一个cookie而不是其他的

例如:

设置完cookie后,我的响应标题将显示为 Set-Cookie:foo1 = testcookie1;,foo2 = testcookie2;,foo3 = testcookie3; 。如果我发出另一个请求,那么请求标头cookie仅包含 foo1 = testcookie1; ,但不包含这些cookie foo2 = testcookie2; foo3 = testcookie3; 即可。这就是问题所在。如果我在响应头中设置了多个cookie,那么它总是只接受后续请求调用中的第一个cookie。

请帮我解决此问题。在此先感谢您的回复。


实施

public class CookieManagerServiceBehaviorAttribute : Attribute, IServiceBehavior
{
    #region IServiceBehavior Members
    public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {
        return;
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
    {
        foreach (ChannelDispatcher channelDispatch in serviceHostBase.ChannelDispatchers)
        {
            foreach (EndpointDispatcher endpointDispatch in channelDispatch.Endpoints)
            {
                endpointDispatch.DispatchRuntime.MessageInspectors.Add(CookieManagerMessageInspector.Instance);
            }
        }
    }

    public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
    {
        return;
    }
    #endregion
}

public class CookieManagerMessageInspector : IDispatchMessageInspector
{
    private static CookieManagerMessageInspector instance;
    private CookieManagerMessageInspector() { }
    public static CookieManagerMessageInspector Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new CookieManagerMessageInspector();
            }
            return instance;
        }
    }

    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        return null;
    }

    public void BeforeSendReply(ref Message reply, object correlationState)
    {
        HttpResponseMessageProperty httpResponse;
        if (!reply.Properties.ContainsKey(HttpResponseMessageProperty.Name))
        {
            reply.Properties.Add(HttpResponseMessageProperty.Name, new HttpResponseMessageProperty());
        }
        httpResponse = (HttpResponseMessageProperty)reply.Properties[HttpResponseMessageProperty.Name];
        foreach (Cookie cookie in RenderContext.Current.PendingCookies)
        {
            if (cookie.Expires > DateTime.Now)
                httpResponse.Headers.Add(HttpResponseHeader.SetCookie, "{0}={1}; expires={2}".StringFormat(cookie.Name, cookie.Value, DateTime.Now.AddYears(1).ToUniversalTime()) + ";");
            else
                httpResponse.Headers.Add(HttpResponseHeader.SetCookie, "{0}={1};".StringFormat(cookie.Name, cookie.Value));
        }
    }
}

1 个答案:

答案 0 :(得分:3)

在构建Web代理时遇到了同样的问题。我需要将目标HttpWebResponse中的Set-Cookie标头中继到代理HttpListenerResponse。如果Set-Cookie标头中有多个Cookie,则第一个将在浏览器中注册。

当我遍历标题的值集(或者在你的情况下是Cookie集合)并使用了response.AppendHeader(header,value)表单时,我能够使它工作。

string[] cookies = response.Headers.GetValues("Set-Cookie");
foreach (string value in cookies)
    clientResponse.AppendHeader("Set-Cookie", value);

因此,在您的情况下,我会将代码的结尾更改为:

if (cookie.Expires > DateTime.Now)
     httpResponse.AppendHeader(HttpResponseHeader.SetCookie, "{0}={1}; expires={2}".StringFormat(cookie.Name, cookie.Value, DateTime.Now.AddYears(1).ToUniversalTime()) + ";");
else
     httpResponse.AppendHeader(HttpResponseHeader.SetCookie, "{0}={1};".StringFormat(cookie.Name, cookie.Value));