1

I need to use WebClient to attain url that is inside response header, after succesfull POST request.

However the headers I get after executing WebClient.UploadValues is the one from page after being redirected.

Using browser (red to highlight the header I need): enter image description here

And this code that simulates same actions as in Browser with WebClient:

NameValueCollection formData = new NameValueCollection();
formData["username"] = user;
formData["password"] = password;

byte[] responseBytes = webClient.UploadValues(loginUrl, "POST", formData);
string response = Encoding.UTF8.GetString(responseBytes);

string allheaders = "";
for (int i = 0; i < webClient.ResponseHeaders.Count; i++)
{
    allheaders += Environment.NewLine + webClient.ResponseHeaders.GetKey(i) + " = " + webClient.ResponseHeaders.Get(i);                        
}
File.WriteAllText("headers_2.txt", "[HEADER_2] " + allheaders);

...gives as a result headers_2.txt that doesn't contain Location header (these headers are from the page that user is redirected to):

[HEADER_2] Pragma = no-cache Cache-Control = no-store, no-cache, must-revalidate Date = Wed, 14 Feb 2018 10:58:10 GMT Expires = Thu, 19 Nov 1981 08:52:00 GMT P3P = fffff Set-Cookie = sid=ffffff; path=/,gameapi_console=0; expires=Sat, 17-Mar-2018 10:58:10 GMT; Max-Age=2678400; path=/,bptid=ffffff; path=/ Server = Apache Vary = Accept-Encoding,User-Agent Access-Control-Allow-Origin = * Content-Type = text/html; charset=UTF-8 Transfer-Encoding = chunked

How to get Location header with WebClient? If I can whatsoever.

UPDATE:

Thanks for comments.

I forgot to show what I tried. So I created my own class that inherits from WebClient. I was thinking that if I read the Headers just in the moment when UploadValuesCompleted is fired - I will have the headers before being automatically redirected. Unfortunately for unknown reason the event is never fired even after I do call webClient.UploadValues(loginUrl, "POST", formData).

class FAWebClient : WebClient
{
    public event Action<string> OnLocationHeaderFound;

    public FAWebClient(Action<string> pOnLocationHeaderFound = null) :base()
    {
        UploadValuesCompleted += OnUploadValuesCompleted;

        if(pOnLocationHeaderFound != null)
            this.OnLocationHeaderFound += pOnLocationHeaderFound;
    }

    protected override void OnUploadValuesCompleted(object sender, UploadValuesCompletedEventArgs e) 
    {
        if (this.OnLocationHeaderFound != null)
        {
            for (int i = 0; i < this.ResponseHeaders.Count; i++)
            {
                System.Diagnostics.Debug.WriteLine(this.ResponseHeaders.GetKey(i) + " = " + this.ResponseHeaders.Get(i));

                if (this.ResponseHeaders.GetKey(i).ToLower() == "location")
                {
                    OnLocationHeaderFound(this.ResponseHeaders.Get(i));
                }
            }
        }

        base.OnUploadValuesCompleted(e);
    }
}

Also please be aware I have workaround that problem using HttpClient, simply setitng HttpClient.AllowAutoRedirect to false:

 var handler = new HttpClientHandler()
 {
      AllowAutoRedirect = false
 };

Due to that I had to change a lot in my app logic, but it works. However I keep this question open if anyone will give solution or answer how to achieve that with WebClient.

Jerry Switalski
  • 2,690
  • 1
  • 18
  • 36
  • Does https://stackoverflow.com/questions/690587/using-webclient-in-c-sharp-is-there-a-way-to-get-the-url-of-a-site-after-being-r or https://stackoverflow.com/a/13039113/34092 help? – mjwills Feb 14 '18 at 12:00
  • 2
    If you need more control on your request/response, you should consider using WebRequest/WebResponse, which allows you to set `AllowAutoRedirect = false`. One of questions linked by @mjwills does that, with a class derived from `WebClient`. Note that not all servers/html pages set a Location Header. Some just create a redirection using a http-equiv meta tag with refresh set to 0 or a javascript that sets the new location. When this happens, the `HttpStatusCode` is often 200 (OK) instead of 302 (found) or 301 (moved) or 303 (redirected). Usually in Web Form authentication. – Jimi Feb 14 '18 at 15:24
  • Is there a problem with setting AllowAutoRedirect =false on your custom WebClient's WebRequest?You want another solution? You could override GetWebRequest ,cast the base.GetWebRequest(address) to HttpWebRequest and set AllowAutoRedirect to false – George Vovos Feb 16 '18 at 15:53
  • @GeorgeVovos I will check next week if I can set AllowAutoRedirect in WebClient as you mentioned and post a comment here. And no, I am not looking for other solution - so if that really works feel free to create answer. – Jerry Switalski Feb 16 '18 at 18:12

1 Answers1

3

So,it looks like you already know the solution.
All you have to do know is configure WebClient to use it.
Let's say your server side code looks like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace WebApplication12.Controllers
{
    public class HomeController : Controller
    {
        [HttpPost]
        public ActionResult Login(LoginModel credential)
        {
            //code
            Response.Headers.Add("IndexHeader","IndexHeaderValue");
            return RedirectToAction("About");
        }

        public ActionResult About()
        {
            Response.Headers.Add("AboutHeader", "AboutHeaderValue");
            return View();
        }
    }

    public class LoginModel
    {
        public string username { get; set; }
        public string password { get; set; }
    }
}

You can create a custom WebClient like this:

using System;
using System.Collections.Specialized;
using System.Net;

namespace ConsoleApp18
{
    public class NoRedirectWebClient : WebClient
    {
        protected override WebRequest GetWebRequest(Uri address)
        {
            var temp = base.GetWebRequest(address) as HttpWebRequest;
            temp.AllowAutoRedirect = false;
            return temp;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MakeRequest(new WebClient());//Prints the AboutHeader
            Console.WriteLine();
            MakeRequest(new NoRedirectWebClient());//Prints the IndexHeader
            Console.ReadLine();
        }

        private static void MakeRequest(WebClient webClient)
        {
            var loginUrl = @"http://localhost:50900/Home/Login";
            NameValueCollection formData = new NameValueCollection();
            formData["username"] = "batman";
            formData["password"] = "1234";

            webClient.UploadValues(loginUrl, "POST", formData);

            string allheaders = "";
            for (int i = 0; i < webClient.ResponseHeaders.Count; i++)
                allheaders += Environment.NewLine + webClient.ResponseHeaders.GetKey(i) + " = " +
                              webClient.ResponseHeaders.Get(i);

            Console.WriteLine("******"+webClient.GetType().FullName+"*******");
            Console.Write(allheaders);
        }
    }
}
George Vovos
  • 7,563
  • 2
  • 22
  • 45