38

I am trying to unit test some code, and I need to to replace this:

  HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create( uri );
  httpWebRequest.CookieContainer = new CookieContainer();

with

  WebRequest webRequest = WebRequest.Create( uri );
  webRequest.CookieContainer = new CookieContainer(); 

Basically, how do I get cookies into the request without using a HttpWebRequest?

leppie
  • 115,091
  • 17
  • 196
  • 297
O.O
  • 11,077
  • 18
  • 94
  • 182
  • That would be difficult, since cookies are an HTTP concept. Is there a reason you need to make this change? – dlev Jun 22 '12 at 21:21
  • @dlev - WebRequest will create a HttpWebRequest based on the uri. Hence, if I want to mock up my own WebRequest object and/or register my own uri that also returns a WebRequest, then I do not want to constrain the method to only working with a HttpWebRequest object. – O.O Jun 22 '12 at 21:27
  • 1
    I understand that the run-time type of `webRequest` will be `HttpWebRequest`. But accessing `CookieContainer` requires that the compile-time type be `HttpWebRequest`. Also, you mention not constraining yourself to HTTP, but in that case, cookies don't mean much, since they are an HTTP construct (which is the reason for their absence on `WebRequest` in the first place.) – dlev Jun 22 '12 at 21:30
  • dlev - which is why I'm looking for a run-time way of adding cookies. Imagine if I said if ... then addcookies ^^ – O.O Jun 22 '12 at 21:32
  • Look this page. http://stackoverflow.com/questions/18667931/httpwebrequest-add-cookie-to-cookiecontainer-argumentexception-parameternam it's was helpful for me – user3078823 Dec 08 '13 at 00:08

4 Answers4

40

Based on your comments, you might consider writing an extension method:

public static bool TryAddCookie(this WebRequest webRequest, Cookie cookie)
{
    HttpWebRequest httpRequest = webRequest as HttpWebRequest;
    if (httpRequest == null)
    {
        return false;
    }

    if (httpRequest.CookieContainer == null)
    {
        httpRequest.CookieContainer = new CookieContainer();
    }

    httpRequest.CookieContainer.Add(cookie);
    return true;
}

Then you can have code like:

WebRequest webRequest = WebRequest.Create( uri );
webRequest.TryAddCookie(new Cookie("someName","someValue"));
Rana
  • 1,675
  • 3
  • 25
  • 51
dlev
  • 48,024
  • 5
  • 125
  • 132
  • 5
    This code returns: "The parameter '{0}' cannot be an empty string." on line httpRequest.CookieContainer.Add(cookie);. Any idea? –  Jun 22 '12 at 21:58
  • 2
    @drdigit That's because you didn't create a cookie that included a domain. Also, I'm pretty sure the error string is a bug in the BCL (which, unfortunately, seems to have persisted in 4.5) – dlev Jun 22 '12 at 22:05
  • @drdigit No problem. Thanks for the (possibly inadvertent) bug report! – dlev Jun 22 '12 at 22:12
  • 6
    I had the same problem "The parameter '{0}' cannot be an empty string." As dlev stated, this is because a domain has not been included. However I am running everything on localhost during development (http://localhost:50665/). So for my Cookie object named 'cookie', I added a domain 'localhost' and that fixed it. The correct statement reads cookie.Domain="localhost". Note that I previously tried cookie.Domain="localhost:50665" and that did not work, also I tried cookie.Domain="http://localhost:50665" and that did not work either. You need to just use "localhost". Hope this helps the next guy. – Gary Jul 18 '13 at 06:40
  • I had the same problem ("The parameter '{0}' cannot be an empty string."). After reading @dlev 's comment explaining why that happened, I wrote this piece of code that solved my problem: `webRequest.TryAddCookie(new Cookie("varName", "varValue","/", uri.Host));`. – Xavier Peña Aug 19 '16 at 09:33
7

Try with something like this:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.contoso.com/default.html");
request.CookieContainer = new CookieContainer();
request.CookieContainer.Add(new Cookie("ConstoCookie", "Chocolate Flavour"));
The Godfather
  • 873
  • 11
  • 18
HatSoft
  • 11,077
  • 3
  • 28
  • 43
  • 1
    The question is not about setting cookie to the Response. It's about Creating new WebRequest and setting a cookie for this request (and looking at the tags of the question, executing the request from the unit test). – Marek Musielak Jun 22 '12 at 21:31
  • 3
    this will throw an error `Object reference not set to an...`. First we may need `request.CookieContainer = new CookieContainer();` then call Add method should work. – shashwat Nov 04 '12 at 06:46
6

WebRequest is an abstract class that does not have a CookieContainer property. In addition you can't use the Headers collection (not implemented exception) so any attempt like webRequest.Headers.Add("Cookie", "...") will fail.

Sorry, but you have no chance to use cookies with WebRequest.

Stick on HttpWebRequest and add/edit as many cookies you like using its Headers collection!

  • I didn't do it :) Your "if then addcookies" requirement can be covered by the HttpWebRequest.Headers.Add("Cookie", "..."). –  Jun 22 '12 at 21:46
1

dlev's answer ended up working, but I had problems implementing the solution ("The parameter '{0}' cannot be an empty string."), so I decided to write the full code in case anybody else has similar problems.

My goal was to get the html as a string, but I needed to add the cookies to the web request. This is the function that downloads the string using the cookies:

public static string DownloadString(string url, Encoding encoding, IDictionary<string, string> cookieNameValues)
{
    using (var webClient = new WebClient())
    {
        var uri = new Uri(url);
        var webRequest = WebRequest.Create(uri);
        foreach(var nameValue in cookieNameValues)
        {
            webRequest.TryAddCookie(new Cookie(nameValue.Key, nameValue.Value, "/", uri.Host));
        }                
        var response = webRequest.GetResponse();
        var receiveStream = response.GetResponseStream();
        var readStream = new StreamReader(receiveStream, encoding);
        var htmlCode = readStream.ReadToEnd();                
        return htmlCode;
    }
}   

We are using the code from dlev's answer:

public static bool TryAddCookie(this WebRequest webRequest, Cookie cookie)
{
    HttpWebRequest httpRequest = webRequest as HttpWebRequest;
    if (httpRequest == null)
    {
        return false;
    }

    if (httpRequest.CookieContainer == null)
    {
        httpRequest.CookieContainer = new CookieContainer();
    }

    httpRequest.CookieContainer.Add(cookie);
    return true;
}

This is how you use the full code:

var cookieNameValues = new Dictionary<string, string>();
cookieNameValues.Add("varName", "varValue");
var htmlResult = DownloadString(url, Encoding.UTF8, cookieNameValues);
Xavier Peña
  • 7,399
  • 9
  • 57
  • 99