How to read cookies from HttpResponseMessage? - c#

This is my recent code:
HttpClient authClient = new HttpClient();
authClient.BaseAddress = new Uri("http://localhost:4999/test_db/_session");
authClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var user = new LoginUserSecretModel
{
name = userKey,
password = loginData.Password,
};
HttpResponseMessage authenticationResponse = authClient.PostAsJsonAsync("", user).Result;

The issue I have with many of the answers here is that using CookieContainer uses short-lived HttpClient objects which is not recommended.
Instead, you can simply read the "Set-Cookie" header from the response:
// httpClient is long-lived and comes from a IHttpClientFactory
HttpResponseMessage response = await httpClient.GetAsync(uri);
IEnumerable<string> cookies = response.Headers.SingleOrDefault(header => header.Key == "Set-Cookie").Value;
If the "Set-Cookie" header is not present, cookies will be null.

Try this:
CookieContainer cookies = new CookieContainer();
HttpClientHandler handler = new HttpClientHandler();
handler.CookieContainer = cookies;
HttpClient authClient = new HttpClient(handler);
var uri = new Uri("http://localhost:4999/test_db/_session");
authClient.BaseAddress = uri;
authClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var user = new LoginUserSecretModel
{
name = userKey,
password = loginData.Password,
};
HttpResponseMessage authenticationResponse = authClient.PostAsJsonAsync("", user).Result;
var responseCookies = cookies.GetCookies(uri).Cast<Cookie>();

This is what you need to get a list of cookies;
private async Task<List<Cookie>> GetCookies(string url, string cookieName)
{
var cookieContainer = new CookieContainer();
var uri = new Uri(url);
using (var httpClientHandler = new HttpClientHandler
{
CookieContainer = cookieContainer
})
{
using (var httpClient = new HttpClient(httpClientHandler))
{
await httpClient.GetAsync(uri);
List<Cookie> cookies = cookieContainer.GetCookies(uri).Cast<Cookie>().ToList();
return cookies;
}
}
}
and if you need only one cookie value here's how
private async Task<string> GetCookieValue(string url)
{
var cookieContainer = new CookieContainer();
var uri = new Uri(url);
using (var httpClientHandler = new HttpClientHandler
{
CookieContainer = cookieContainer
})
{
using (var httpClient = new HttpClient(httpClientHandler))
{
await httpClient.GetAsync(uri);
var cookie = cookieContainer.GetCookies(uri).Cast<Cookie>().FirstOrDefault(x => x.Name == cookieName);
return cookie?.Value;
}
}
}

Building on top of Daniel's answer and this answer to another question, this would be an easy way to read the cookies from an HTTP response.
// httpClient is long-lived and comes from a IHttpClientFactory
HttpResponseMessage response = await httpClient.GetAsync(uri);
CookieContainer cookies = new CookieContainer();
foreach (var cookieHeader in response.Headers.GetValues("Set-Cookie"))
cookies.SetCookies(uri, cookieHeader);
string cookieValue = cookies.GetCookies(uri).FirstOrDefault(c => c.Name == "MyCookie")?.Value;

Related

Forwarding a HttpPut request with PutAsync

How do I forward a HttpPut request in c# please?
This is what I have so far but I would like to change SendAsync to PutAsync instead but PutAsync does accept HttpRequestMessage type. I am trying to retain the information from the original request.
public async Task<HttpResponseMessage> MyFunc(HttpRequestMessage request)
{
var url = "http://test.com/stuffgoeshere"
UriBuilder forwardUri = new UriBuilder(url);
request.RequestUri = forwardUri.Uri;
var handler = new HttpClientHandler();
using (var httpClient = new HttpClient(handler))
{
using (var client = new HttpClient(handler))
{
var response = await client.PutAsync(request, HttpCompletionOption.ResponseHeadersRead);
return response;
}
}
}
Http Method(Verb) is already in HttpResponseMessage in property Method and you can set it up or change if you need:
request.Method = HttpMethod.Put;
That's why you can ease use SendAsync with your request:
public async Task<HttpResponseMessage> MyFunc(HttpRequestMessage request)
{
var url = "http://test.com/stuffgoeshere";
UriBuilder forwardUri = new UriBuilder(url);
request.RequestUri = forwardUri.Uri;
request.Method = HttpMethod.Put;
using (var client = new HttpClient())
{
var response = await client.SendAsync(request);
return response;
}
}
Or, if Method in HttpRequestMessage has already set up, just do SendAsync and it works.

Posting unicode data using HttpClient

I am trying to post some unicode data using Http request message. Somehow content encoding is causing some issue. I am not setting any encoding explicitly in my code.
For example, I am trying to send 'รัค' & on client side it is being received as 'รัà¸'.
Sample code
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer, })
using(var httpClient = new HttpClient(handler)){
//set all cookies
foreach (var obj in configurationData["request_cookies"])
{
var cookie = ((JProperty)(obj));
cookieContainer.Add(new Uri(configurationData["request_cookie_base_url"].ToString()),
new Cookie(cookie.Name, HttpUtility.UrlEncode(cookie.Value.ToString())));
}
var request = new HttpRequestMessage();
request.Method = HttpMethod.Post;
request.RequestUri = new Uri(configurationData["form_url"].ToString());
//set all request headers
foreach (var obj in configurationData["request_headers"])
{
var cookie = ((JProperty) (obj));
request.Headers.Add(cookie.Name, cookie.Value.ToString());
}
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
//get request content data from configurationData as keyvalue pair
var contentValue = parsedCrmConfigurationData["form_data_template"]
.ToObject<Dictionary<string, string>>();
request.Content = new FormUrlEncodedContent(contentValue);
var response = httpClient.SendAsync(request).Result;
response.EnsureSuccessStatusCode();
}
Do I need to pass encoding specifically? if yes then how?
Please help me understand the issue.
you can use below code to encode your content
private static HttpContent getencodedContent(string jsonString)
{
var cont = new StringContent(jsonString, Encoding.UTF8, "application/json");
return cont;
}

How use cookie Windows Phone c#

I have problem.
I have code on the main page:
private async Task<string> Login(string username, string password)
{
try
{
string url = "myurl.com/page1";
Uri address = new Uri(url);
var postData = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("Login", username),
new KeyValuePair<string, string>("Password", password)
};
CookieContainer cookieJar = new CookieContainer();
HttpContent content = new FormUrlEncodedContent(postData);
var handler = new HttpClientHandler
{
CookieContainer = cookieJar,
UseCookies = true,
UseDefaultCredentials = false
};
var client = new HttpClient(handler)
{
BaseAddress = address
};
HttpResponseMessage response = await client.PostAsync(url, content);
string UrlBase = "myurl.com/page1";
Uri uri = new Uri(UrlBase);
var responseCookies = cookieJar.GetCookies(uri);
foreach (Cookie cookie in responseCookies)
{
string cookieName = cookie.Name;
string cookieValue = cookie.Value;
}
response.EnsureSuccessStatusCode();
string body = await response.Content.ReadAsStringAsync();
return body;
}
catch (Exception e)
{
return e.ToString();
}
}
But in debug I cant see cookies. And his number is 0.
And I don`t know, how can I get myurl.com/page2 on the Page2.xaml?
How to use and save cookies?
How to get and set cookies for Windows Phone 8
http://msdn.microsoft.com/en-us/library/windowsphone/develop/dd920298(v=vs.105).aspx

Adding authorization to the headers

I have the following code:
...
AuthenticationHeaderValue authHeaders = new AuthenticationHeaderValue("OAuth2", Contract.AccessToken);
string result = await PostRequest.AuthenticatedGetData(fullUrl, null, authHeaders);
return result;
...
public static async Task<string> AuthenticatedGetData(string url, FormUrlEncodedContent data, AuthenticationHeaderValue authValue)
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authValue.Parameter);
HttpResponseMessage response = await client.PostAsync(new Uri(url), data);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
return responseBody;
}
The response = await part just continues an ongoing loop and nothing happens. Any ideas what I am doing wrong?
The question really is, how do I send the following header:
Authorization: OAuth2 ACCESS_TOKEN
to an external web api
I struggled with this. I kept getting an error saying "invalid format" because I have a custom implementation and the Authorization header is validated against certain standards. Adding the header this way however worked:
var http = new HttpClient();
http.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "key=XXX");
This line
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(authValue.Parameter);
Will produce this header value
Authorization: ACCESS_TOKEN
Where ACCESS_TOKEN is the value of authValue.Parameter. You want to assign the value you passed instead to get the required header
client.DefaultRequestHeaders.Authorization = authValue;
Will produce
Authorization: OAuth2 ACCESS_TOKEN
Had a similar issue when getting AuthenticationHeaderValue to work with my requests.
I was also using JWT JsonWebToken from GitHub.
I was able to get a token from the API, but was struggling to use it in other GETs and POSTs.
var jwt = JsonWebToken.Encode(token, APISECRET, JwtHashAlgorithm.HS256);
var tk = GetTokenFromApi(); // basically returns an encrypted string.
Manually using WebRequest:
Which worked fine.
request.ContentType = "application/json";
request.Method = "POST";
request.Headers.Set("Authorization", string.Format("Bearer {0}", tk));
When we switched to an HttpClient, and used the AuthenticationHeaderValue, could not figure out how to set it up correctly.After looking at the request string, i saw it added the "Authorization" for me. Played around with parameters, and this finally this worked.
var authenticationHeaderValue = new AuthenticationHeaderValue("Bearer", tk);
Maybe intresting for other people. Since I searched on this for a long time. But you have to save your cookies also and give it with your next request. First this is how i got my authentication code and hold my cookies in a static variable (in the first time i call this method I give an empty value to token).
public static CookieContainer CookieContainer;
public static async Task<string> Post<TRequest>( TRequest requestBody, string path, string token = "")
{
var baseUrl = new Uri($"urlFromApi");
CookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = CookieContainer })
using(var client = new HttpClient(handler){BaseAddress = baseUrl})
{
client.DefaultRequestHeaders.ConnectionClose = false;
if (!string.IsNullOrWhiteSpace(token))
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", $"{token}");
}
ServicePointManager.FindServicePoint(client.BaseAddress).ConnectionLeaseTimeout = 60 * 1000; //1 minute using (var content = new ByteArrayContent(GetByteData(requestBody)))
using (var content = new ByteArrayContent(GetByteData(requestBody)))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await client.PostAsync(String.Empty, content);
return await GetResponseContent(response);
}
}
}
After this if I do any request to the api I include the cookies (token is what you get from the first response as a result)
public static async Task Get(string path, string token = "")
{
var baseUrl = $"https://innoviris-ai.collibra.com/rest/2.0{path}";
using (var handler = new HttpClientHandler() { CookieContainer = CookieContainer })
using (var client = new HttpClient(handler) {BaseAddress = new Uri(baseUrl)})
{
client.DefaultRequestHeaders.ConnectionClose = false;
if (!string.IsNullOrWhiteSpace(token))
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", $"{token}");
}
ServicePointManager.FindServicePoint(client.BaseAddress).ConnectionLeaseTimeout = 60 * 1000; //1 minute
var response = await client.GetAsync(String.Empty);
return await GetResponseContent(response);
}
}
In your code you are doing this:
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", $"{token}");
I think the following should work the same manner without using string interpolation:
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
This is because the string interpolation is just generating a string with the token in it!

Struggling trying to get cookie out of response with HttpClient in .net 4.5

I've got the following code that works successfully. I can't figure out how to get the cookie out of the response. My goal is that I want to be able to set cookies in the request and get cookies out of the response. Thoughts?
private async Task<string> Login(string username, string password)
{
try
{
string url = "http://app.agelessemail.com/account/login/";
Uri address = new Uri(url);
var postData = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("username", username),
new KeyValuePair<string, string>("password ", password)
};
HttpContent content = new FormUrlEncodedContent(postData);
var cookieJar = new CookieContainer();
var handler = new HttpClientHandler
{
CookieContainer = cookieJar,
UseCookies = true,
UseDefaultCredentials = false
};
var client = new HttpClient(handler)
{
BaseAddress = address
};
HttpResponseMessage response = await client.PostAsync(url,content);
response.EnsureSuccessStatusCode();
string body = await response.Content.ReadAsStringAsync();
return body;
}
catch (Exception e)
{
return e.ToString();
}
}
Here is the complete answer:
HttpResponseMessage response = await client.PostAsync(url,content);
response.EnsureSuccessStatusCode();
Uri uri = new Uri(UrlBase);
var responseCookies = cookieJar.GetCookies(uri);
foreach (Cookie cookie in responseCookies)
{
string cookieName = cookie.Name;
string cookieValue = cookie.Value;
}
To add cookies to a request, populate the cookie container before the request with CookieContainer.Add(uri, cookie). After the request is made the cookie container will automatically be populated with all the cookies from the response. You can then call GetCookies() to retreive them.
CookieContainer cookies = new CookieContainer();
HttpClientHandler handler = new HttpClientHandler();
handler.CookieContainer = cookies;
HttpClient client = new HttpClient(handler);
HttpResponseMessage response = client.GetAsync("http://google.com").Result;
Uri uri = new Uri("http://google.com");
IEnumerable<Cookie> responseCookies = cookies.GetCookies(uri).Cast<Cookie>();
foreach (Cookie cookie in responseCookies)
Console.WriteLine(cookie.Name + ": " + cookie.Value);
Console.ReadLine();
There's alternative if you don't have access to the HttpClient and can't inject the CookieContainer. This works in .NET Core 2.2:
private string GetCookie(HttpResponseMessage message)
{
message.Headers.TryGetValues("Set-Cookie", out var setCookie);
var setCookieString = setCookie.Single();
var cookieTokens = setCookieString.Split(';');
var firstCookie = cookieTokens.FirstOrDefault();
var keyValueTokens = firstCookie.Split('=');
var valueString = keyValueTokens[1];
var cookieValue = HttpUtility.UrlDecode(valueString);
return cookieValue;
}
You can easily get a cookie value with the given URL.
private async Task<string> GetCookieValue(string url, string cookieName)
{
var cookieContainer = new CookieContainer();
var uri = new Uri(url);
using (var httpClientHandler = new HttpClientHandler
{
CookieContainer = cookieContainer
})
{
using (var httpClient = new HttpClient(httpClientHandler))
{
await httpClient.GetAsync(uri);
var cookie = cookieContainer.GetCookies(uri).Cast<Cookie>().FirstOrDefault(x => x.Name == cookieName);
return cookie?.Value;
}
}
}
Not in every case you can add httpClientHandler to httpClient. For example, when you use integration tests testServer.CreateClient() or inject httpClient from IHttpClientFactory. So, I have simply read values from header.
public static List<Cookie> GetCookies(this HttpResponseMessage message)
{
message.Headers.TryGetValues("Set-Cookie", out var cookiesHeader);
var cookies = cookiesHeader.Select(cookieString => CreateCookie(cookieString)).ToList();
return cookies;
}
private static Cookie CreateCookie(string cookieString)
{
var properties = cookieString.Split(';', StringSplitOptions.TrimEntries);
var name = properties[0].Split("=")[0];
var value = properties[0].Split("=")[1];
var path = properties[2].Replace("path=", "");
var cookie = new Cookie(name, value, path)
{
Secure = properties.Contains("secure"),
HttpOnly = properties.Contains("httponly"),
Expires = DateTime.Parse(properties[1].Replace("expires=", ""))
};
return cookie;
}
CreateCookie method may be modified to exactly match your cookie properties.

Categories