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

Vin*_*bbe 7 c# system.web httpcookiecollection

HttpCookieCollection.Get MSDN文档中,声明:

如果指定的cookie不存在,则此方法将创建具有该名称的新cookie.

这是真的,在调用时HttpContext.Request.CookiesHttpContext.Response.Cookies从"真正的"Web服务器运行良好.

但是,这段代码:

    HttpCookieCollection foo = new HttpCookieCollection();
    HttpCookie cookie = foo.Get("foo");
    Console.WriteLine(cookie != null);
Run Code Online (Sandbox Code Playgroud)

显示False(cookie为空).

如果HttpCookieCollectionRequest.CookiesHTTP处理程序中检索,则不是这种情况.

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

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

谢谢您的帮助

Dav*_*ore 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;
}
Run Code Online (Sandbox Code Playgroud)

它永远不会创建cookie,因为_response将为null(查看第一个'if'语句).即没有响应对象将新cookie发回,因此不会创建它.

响应对象是一个HttpResponse对象,它被传递给内部构造函数(因此构造函数不可用).

我个人从不喜欢Get方法对HttpCookieCollection的作用方式; 它违反了Command-Query分离原则:提问不应该改变答案.

我建议您通过检查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;
    }
}
Run Code Online (Sandbox Code Playgroud)