HttpRequestMessage multiple custom headers overwriting each other - c#

I am struggling to understand how to add MULTIPLE headers to the HttpRequestMessage. I mean I get the basics and if I do one header it works but multiple headers and the last one is what sticks and all others are overwritten?
So for example the Accept header will be overwritten but the authorization header will stick.
HttpRequestMessage httpreqmsg = new HttpRequestMessage();
httpreqmsg.Headers.Add("Accept", "CustomAccept");
httpreqmsg.Headers.Add("Authorization", "asdfas#%fwqerq#werfds...");
Now HttpRequestMessage has an overload with the signature
.Add(string, List<string>)
and that is fine if you have ONE name with multiple values but how do you do multiple headers. TryAddWithoutValidation has the same overloads as above?
TIA
Great...so I kinda made a mistake in my post. I didn't think it mattered but it does. I am unit testing a controller and therefore there is no HttpClient object created.

It seems the "Accept" header is reserved. No matter what value I tried to assign to it a FormatException was thrown.
If you change your code to this you get both headers back.
HttpRequestMessage httpreqmsg = new HttpRequestMessage();
httpreqmsg.Headers.Add("Lolz", "CustomAccept");
httpreqmsg.Headers.Add("Authorization", "SomeValue");
foreach (var item in httpreqmsg.Headers)
{
Console.WriteLine(item.Key + " : " + item.Value);
}
Also the value of 'Authorization' in your example was invalid, but I'm guessing that was just random key mashing :)

Not sure about the context of your code, but you could use HttpClient (WebApi NuGet) instead, which lets you add "Accept" and "Authorization" headers:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("scheme", "param");
//client.PostAsJsonAsync or something else
}

Building on #sidjames's post. It seems you're looking for the Accept and Authorization headers. If that's the case, then set it in HttpClient, instead of the HttpRequestMessage:
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("some accept"));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", "your parameters");
There are a bunch of examples for accept and authorization on the StackOverflow.

Related

HttpClient Authorization Header not being send when set BrowserRequestMode to NoCors

I'm trying to send a request like this:
var req = new HttpRequestMessage(HttpMethod.Get, requestUri);
req.SetBrowserRequestMode(BrowserRequestMode.NoCors);
req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken);
var resp = await httpClient.SendAsync(req, cancellationToken);
I see that authrozation header that I set does not send. But if I remove the 2nd line it will send. I need to set the 2nd line.
Why it should not send authorization when setting BrowserRequestMode to NoCors?
from msdn web docs :
no-cors — Prevents the method from being anything other than HEAD, GET
or POST, and the headers from being anything other than simple
headers.
Simple headers are what we call CORS-safelisted request headers like :
Accept
Accept-Language
Content-Language
Content-Type
Authorization header is not being sent because in your second line you're preventing that header from being sent by enabling cors.
I don't know if you're doing that for some purpose or not but I think it's a cors related thing , your code is correct. There are plenty of answers explaining CORS out there.
According MDN - no-cors — Prevents the method from being anything other than HEAD, GET or POST, and the headers from being anything other than simple headers. Bearer is not included in the simple headers list.
And I recommend you to use this syntax for the Bearer:
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

HttpRequestMessage won't allow Authorization header value

I'm trying to reuse my HttpClient instance, as that's best practice. Therefore, in one particular request, I want to set the Authorization header on the request, instead of setting it globally on the client. From everything I've read, this ought to work:
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await _client.SendAsync(request);
This compiles, but then throws when I attempt to call it. The exception I get is:
"Misused header name. Make sure request headers are used with
HttpRequestMessage, response headers with HttpResponseMessage, and
content headers with HttpContent objects."
I'm confused why I'm allowed to set this value on the request message if it's just going to throw, and I also haven't figured out a workaround.
I've tried directly adding the header using TryAddWithoutValidation but I still get the same exception (not even a return of false like I'd expect!)
I'm suspecting this might be a bug in the framework since multiple people have posted this exact code with no apparent problems, but would be interested in any insights/workarounds.
Turns out that due to a different bug, the value of "token" was null. I would recommend checking this first if you're having this issue: note that the error message was 100% a lie.

GET call to a Google API responds with "Unauthorized"

UPDATE: Figured this out. I DID need to add the authorization header as answered below but I also believe the issue for my particular use case is that the access token (which I verified through Postman) required more scopes to authenticate me fully, which makes sense since this API contains surveys that I am trying to access, which are also linked to a Google account. Once I added the extra scopes needed to access the surveys to the token request along with the authorization header code below I was able to connect successfully.
More info on adding scopes to C# code can be found here: http://www.oauthforaspnet.com/providers/google/
Hope this helps anyone running into similar issues. Thanks all!
I am trying to make a GET call to a Google API but it keeps responding with "Unauthorized" while I am logged in to Gmail. I've already implemented Google+ Sign-In in StartUp.Auth.cs and even saved the access token for later use.
So how do I get the HttpClient to authorize me?
I have an access token available but I do not know how to pass it in properly. I've seen examples with usernames and passwords, but I should not need to pass those parameters if I already have an access token? If anything, I should be able to have the user redirected to a login page instead if needed when I log out before running the solution.
What I am expecting when the project is run, is the result of the GET call to come back in the form of json but it always says I'm "Unauthorized" and I am probably missing 1 line of code somewhere...
Here is the code I am using:
using (HttpClient client = new HttpClient())
{
string _url = "https://www.googleapis.com/consumersurveys/v2/surveys?key={MY_API_KEY}";
client.BaseAddress = new Uri(_url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
using (HttpResponseMessage response = client.GetAsync(_url).Result)
{
if (response.IsSuccessStatusCode)
{
using (HttpContent content = response.Content)
{
var Content = content.ReadAsStringAsync();
ViewBag.GoogleResponse = Content.ToString();
}
}
else
{
// THIS IS ALWAYS UNAUTHORIZED!
ViewBag.GoogleResponse = response.StatusCode + " - " + response.ReasonPhrase;
}
}
}
Please help with ideas or suggestions. Thanks!
You need to pass the auth token in an Authorization Header:
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
Have you ever gotten an response for this api/survey? If you were unable to get a response from the API by hitting it with Postman, you may have issues in the way you are targeting the API. The error being returned there seems like you weren't including the token in your request header. Did you click the Authorization tab below the request URL to add the OAuth token to your header? (Keep in mind that the {} characters need to be URL encoded)
Also, when you are referencing MY_API_KEY, is that analagous to your surveyId?
I don't have a lot of experience here, but I have a couple of suggestions :
1) I agree with Pedro, you definitely need to include the Authorization Header in your request.
2) If your MY_API_KEY is in fact the survey ID, you may be providing an incorrect URL (GoogleAPIs documentation indicates that it should be < http://www.googleapis.com/consumer-surveys/v2/surveys/surveyId >
Recommendation (after moving your API key to a string var named MY_API_KEY) :
string _url = "https://www.googleapis.com/consumersurveys/v2/surveys/";
client.BaseAddress = new Uri(_url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ViewBag.GoogleAccessToken);
using (HttpResponseMessage response = client.GetAsync(MY_API_KEY).Result)
{
if (response.IsSuccessStatusCode)
{
using (HttpContent content = response.Content)
{
var Content = content.ReadAsStringAsync();
ViewBag.GoogleResponse = Content.ToString();
}
}
Reference:
https://developers.google.com/consumer-surveys/v2/reference/
http://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client

C# How to pass on a cookie using a shared HttpClient

I have the following set up:
JS client -> Web Api -> Web Api
I need to send the auth cookie all the way down. My problem is sending it from one web api to another. Because of integration with an older system, that uses FormsAuthentication, I have to pass on the auth cookie.
For performance reasons I share a list of HttpClients (one for each web api) in the following dictionary:
private static ConcurrentDictionary<ApiIdentifier, HttpClient> _clients = new ConcurrentDictionary<ApiIdentifier, HttpClient>();
So given an identifier I can grab the corresponding HttpClient.
The following works, but I'm pretty sure this is bad code:
HttpClient client = _clients[identifier];
var callerRequest = HttpContext.Current.Items["MS_HttpRequestMessage"] as HttpRequestMessage;
string authCookieValue = GetAuthCookieValue(callerRequest);
if (authCookieValue != null)
{
client.DefaultRequestHeaders.Remove("Cookie");
client.DefaultRequestHeaders.Add("Cookie", ".ASPXAUTH=" + authCookieValue);
}
HttpResponseMessage response = await client.PutAsJsonAsync(methodName, dataToSend);
// Handle response...
Whats wrong about this is that 1) it seems wrong to manipulate DefaultRequestHeaders in a request and 2) potentially two simultanious requests may mess up the cookies, as the HttpClient is shared.
I've been searching for a while without finding a solution, as most having a matching problem instantiates the HttpClient for every request, hence being able to set the required headers, which I'm trying to avoid.
At one point I had get requests working using a HttpResponseMessage. Perhaps that can be of inspiration to a solution.
So my question is: is there a way to set cookies for a single request using a HttpClient, that will be safe from other clients using the same instance?
Instead of calling PutAsJsonAsync() you can use HttpRequestMessage and SendAsync():
Uri requestUri = ...;
HttpMethod method = HttpMethod.Get /*Put, Post, Delete, etc.*/;
var request = new HttpRequestMessage(method, requestUri);
request.Headers.TryAddWithoutValidation("Cookie", ".ASPXAUTH=" + authCookieValue);
request.Content = new StringContent(jsonDataToSend, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
UPDATE:
To make sure that your HTTP client does not store any cookies from a response you need to do this:
var httpClient = new HttpClient(new HttpClientHandler() { UseCookies = false; });
Otherwise you might get unexpected behavior by using one client and sharing other cookies.

HttpClient request header customisation

Is it possible to set the request ACCEPT header of the HttpClient in .Net/Web Api to include "application/json;odata=verbose"?
I know how to set the request media type
HttpClient client = new HttpClient(handler);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
But how do I set the odata=verbose part? I cannot seem to find any solutions online to do that.
Do I have to use HttpWebRequest instead? Basically I need to call sharepoint 2013 rest api, and that odata=verbose part is required.
MediaTypeWithQualityHeaderValue has a property called Parameters to which you can add 'odata=verbose' parameter.
Other easy way is to call MediaTypeWithQualityHeaderValue's Parse/TryParse methods to which you can supply the whole "application/json;odata=verbose" media type string.
Here is an example using Parse
using (HttpClient httpClient = new HttpClient())
{
//Setup Accept Header
MediaTypeWithQualityHeaderValue acceptHeader = MediaTypeWithQualityHeaderValue.Parse("application/json;odata=verbose");
httpClient.DefaultRequestHeaders.Accept.Add(acceptHeader);
//... do other stuff
}

Categories

Resources