在HttpCookieCollection.Get MSDN documentation中,声明:
如果指定的cookie不存在,则此方法会创建一个新cookie 用那个名字。
这是正确的,并且在从“真正的”网络服务器调用HttpContext.Request.Cookies
或HttpContext.Response.Cookies
时效果很好。
但是,这段代码:
HttpCookieCollection foo = new HttpCookieCollection();
HttpCookie cookie = foo.Get("foo");
Console.WriteLine(cookie != null);
显示False
(cookie
为空)。
如果在HTTP处理程序中从HttpCookieCollection
检索Request.Cookies
,则不是这种情况。
如果需要任何其他设置,请知道这里有什么问题?
我问这个是因为我在模拟HttpContextBase的地方编写单元测试,因此没有提供“真实”的上下文。
感谢您的帮助
答案 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;
}
}