为什么HttpCookieCollection.当从手动实例化的对象(而不是从当前HttpContext)调用时,Get

本文关键字:HttpContext Get 调用 HttpCookieCollection 实例化 为什么 对象 | 更新日期: 2023-09-27 18:12:30

在HttpCookieCollection中。获取MSDN文档,说明:

如果指定的cookie不存在,这个方法创建一个新的cookie用那个名字。

这是真的,并且在从"真实的"web服务器调用HttpContext.Request.CookiesHttpContext.Response.Cookies时工作得很好。

但是,这段代码:

    HttpCookieCollection foo = new HttpCookieCollection();
    HttpCookie cookie = foo.Get("foo");
    Console.WriteLine(cookie != null);

显示False (cookie为空)。

如果在HTTP处理程序中从Request.Cookies中检索HttpCookieCollection,则不是这种情况。

是否知道这里有什么问题/是否需要任何其他设置?

我问这个问题是因为我写单元测试,我模拟HttpContextBase,所以没有提供"真正的"上下文。

谢谢你的帮助

为什么HttpCookieCollection.当从手动实例化的对象(而不是从当前HttpContext)调用时,Get

如果查看HttpCookieCollection.Get(string)的代码,您将看到如下内容:

public HttpCookie Get(string name)
{
  HttpCookie cookie = (HttpCookie) this.BaseGet(name);
  if (cookie == null && this._response != null)
  {
    cookie = new HttpCookie(name);
    this.AddCookie(cookie, true);
    this._response.OnCookieAdd(cookie);
  }
  if (cookie != null)
    this.EnsureKeyValidated(name, cookie.Value);
  return cookie;
}

它永远不会创建cookie,因为_response将为null(查看第一个'if'语句)。也就是说,没有响应对象来发送新的cookie,所以它不会创建它。

响应对象是一个HttpResponse对象,它被传递给内部构造函数(所以构造函数对你来说是不可用的)。

我个人从来不喜欢Get方法在HttpCookieCollection上的行为方式;它违反了命令-查询分离原则:提出问题不应该改变答案。

我建议你通过检查AllKeys属性来检查cookie是否存在;如果不存在,则显式地创建该cookie并将其添加到集合中。否则,如果知道键存在,则继续获取现有条目。然后你的产品代码和单元测试应该正常运行。

这可能是一个好主意,创建一个助手或扩展方法来代替Get,以确保它的行为如你所期望的,无论你是单元测试或正常运行:

public static class HttpCookieCollectionExtensions
{
    public static HttpCookie GetOrCreateCookie(this HttpCookieCollection collection, string name)
    {
        // Check if the key exists in the cookie collection. We check manually so that the Get
        // method doesn't implicitly add the cookie for us if it's not found.
        var keyExists = collection.AllKeys.Any(key => string.Equals(name, key, StringComparison.OrdinalIgnoreCase));
        if (keyExists) return collection.Get(name);
        // The cookie doesn't exist, so add it to the collection.
        var cookie = new HttpCookie(name);
        collection.Add(cookie);
        return cookie;
    }
}