This turned out to be harder than I thought. I had to not only figure out how to post form fields using .Net code but also handle anti-forgery cookies and hidden fields.
When you request a protected URL, the browser is redirected to the login page. The header of this response contains a Set-Cookie header and the body a hidden input. When the login form is posted, these must be sent back and match.
Here is some example code that does all this (replace < with < and & with &):
private string LogIn(string startUrl) { try { //var proxy = new WebProxy("127.0.0.1", 8888); // Fiddler IWebProxy proxy = null; // Make the request. This will result in the login page being returned. var request = WebRequest.CreateHttp(startUrl); request.Proxy = proxy; var response = (HttpWebResponse)request.GetResponse(); Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK)); // Get request verification token cookie: string setCookie = response.Headers["Set-Cookie"]; Assert.That(setCookie, Is.Not.Null); var requestVerificationTokenCookie = setCookie.Split(';')[0]; // Get form action to be posted to later: string responseBody = new StreamReader(response.GetResponseStream()).ReadToEnd(); var regex = new Regex("form action=\"([^\"]*)\""); Assert.That(regex.IsMatch(responseBody)); string formAction = regex.Match(responseBody).Groups[1].Value; Assert.That(formAction, Is.Not.Null); // Get request verification token form field: regex = new Regex("<input name=\"__RequestVerificationToken\" .*? value=\"([^\"]*)\""); Assert.That(regex.IsMatch(responseBody)); string requestVerificaitonToken = regex.Match(responseBody).Groups[1].Value; // Post the login form: var baseUri = new Uri(Properties.Settings.Default.AppUrl); var localUri = new Uri(formAction, UriKind.Relative); var loginUri = new Uri(baseUri, localUri); request = WebRequest.CreateHttp(loginUri); request.Proxy = proxy; request.Method = HttpMethod.Post.Method; request.Headers.Add(HttpRequestHeader.Cookie, requestVerificationTokenCookie); string postData = $"__RequestVerificationToken={requestVerificaitonToken}&UserId={Properties.Settings.Default.UserId}&Password={Properties.Settings.Default.Password}"; byte[] byteArray = Encoding.UTF8.GetBytes(postData); request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = byteArray.Length; Stream dataStream = request.GetRequestStream(); dataStream.Write(byteArray, 0, byteArray.Length); dataStream.Close(); request.AllowAutoRedirect = false; // Prevents redirecting back to returnUrl. response = (HttpWebResponse) request.GetResponse(); Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.Found)); // Redirect to original url setCookie = response.Headers["Set-Cookie"]; Assert.That(setCookie, Is.Not.Null); var sessionCookie = setCookie.Split(';')[0]; return sessionCookie; } catch (WebException ex) { Assert.Fail(ex.ToString()); return null; } }
Now, this can be used in a test like this:
[Test] public void Test1() { string url = "http://localhost/..."; string sessionCookie = LogIn(url); var response = Request(sessionCookie, url); Assert.That(response, Contains.Substring("(Some string that is always in correct response)")); } private static string Request(string sessionCookie, string url) { var webClient = new WebClient(); webClient.Headers.Add(HttpRequestHeader.Cookie, sessionCookie); string response = webClient.DownloadString(url); return response; }