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

时间:2013-05-06 14:50:37

标签: c# system.web httpcookiecollection

HttpCookieCollection.Get MSDN documentation中,声明:

  

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

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

但是,这段代码:

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

显示Falsecookie为空)。

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

如果需要任何其他设置,请知道这里有什么问题?

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

感谢您的帮助

1 个答案:

答案 0 :(得分:8)

如果你看一下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的行为方式;它违反了Command-Query separation原则:提问不应该改变答案。

我建议您通过检查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;
    }
}