8

HttpCookieCollection.Get MSDN 文档中,声明:

如果指定的 cookie 不存在,此方法会创建一个具有该名称的新 cookie。

这是真的,并且在调用HttpContext.Request.CookiesHttpContext.Response.Cookies从“真实”Web 服务器调用时效果很好。

但是,这段代码:

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

显示Falsecookie为空)。

如果从HTTP 处理程序HttpCookieCollection中检索 ,则情况并非如此。Request.Cookies

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

我问这个是因为我在模拟 HttpContextBase 的地方编写单元测试,所以没有提供“真实”的上下文。

谢谢您的帮助

4

1 回答 1

10

如果您查看 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 将为空(查看第一个“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;
    }
}
于 2013-07-11T21:12:59.323 回答