System.FormatException when adding User-Agent with colon - c#

I am trying to make a http request like this one https://tools.keycdn.com/geo.json?host=google.com in C#. For this, according to the https://tools.keycdn.com/geo?host=google.com, I have to add user agent like this
User-Agent: keycdn-tools:https://myownsite.com
I am doing the request with this code:
HttpClient? client = new HttpClient();
// Add correct user agent.
var request = new HttpRequestMessage(HttpMethod.Get, "https://tools.keycdn.com/geo.json?host=" + textBoxDomain.Text);
var useragentValue = new ProductInfoHeaderValue("keycdn-tools:https://myownsite.com");
request.Headers.UserAgent.Add(useragentValue);
var result = await client.SendAsync(request);
But I get the System.FormatException when adding the user agent.
How can I resolve this problem?
Edit
I tried to solve the problem by adding DefaultRequestHeaders directly to client object, but I got the same error message
Then I tried to add the header to the request, but there I got also the same error message

.NET's ProductInfoHeaderValue helper class is enforcing syntax restrictions that the HTTP specification doesn't require for User-Agent because the purpose of this class is to create a value that follows the RFC's specification for product tokens.
You can instead add User-Agent directly to the Headers collection:
request.Headers.Add("User-Agent", "keycdn-tools:https://myownsite.com");
If you wish to set the same user agent for every request made by that request instance:
client.DefaultRequestHeaders.Add("User-Agent", "my-user-agent-name");

Related

Obtain the entire http Request including headers prior to a request being sent to the server

I can obtain the details of my http request including headers via Fiddler, however I'd like to display the value of my http request and response as part of my MVC web service to ensure the request is valid.
I want to return all of the details of the request as a string so I can return the result to the View for this specific controller.
I am using C# to create the request:
var _httpClientManager = new HttpClientManager(_httpClientPool, _Identity, _errorLogger);
_httpClientManager.HttpRequestHeaders = new Dictionary<string, string>();
_httpClientManager.HttpRequestHeaders.Add("Accept", "application/json");
... extra headers omitted.....
... url and request JSON is omitted
var response = await _httpClientManager.PostAsJsonAsync<IdentityVerificationRequest>(url, request, null);
return View(response);
Basically I'd like to obtain what I am about to Post to the server and include that in the View response.
Its probably a bit of a naïve question, I am quite new working with this.
Is it possible?
Thankyou.

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);

How to send a GET request exactly like I have it in fiddler?

So I am trying to build a program in C#. I want to send a really specific request. Exactly as I receive it in fiddler. Right now I am using fiddlers composer feature to send the request. Here is how I get the request in fiddler
How can I send it exactly as shown on the picture but in a C# console application?
Basically looking for a way to get a request in fiddler and implement it directly in to my code in the format that fiddler gives it to me.(In fiddler I can save the request in .txt format. If I could use that same .txt format to send the request then it would be really helpful)
You need to create HttpClient instance and set the headers shown in the fiddler to the same values. Hope this helps. Your URL was HTTPS hence you will need to set for certificate validation OR you will have to set avoid certificate errors on the call.
// Create a client
HttpClient httpClient = new HttpClient();
// Add a new Request Message
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Put, "https://yoursitehere/");
// Add our custom headers
requestMessage.Headers.Add("User-Agent", "User-Agent-Here");
requestMessage.Headers.Add("Connection", "MIME-Type-Here");
requestMessage.Headers.Add("Cache-Control", "value-from-fiddler");
requestMessage.Headers.Add("Accept-Language", "value-from-fiddler");
requestMessage.Headers.Add("Accept-Encoding", "value-from-fiddler");
requestMessage.Headers.Add("Accept", "value-from-fiddler");
requestMessage.Headers.Add("User-Agent", "value-from-fiddler");
// Send the request to the server
HttpResponseMessage response = await httpClient.SendAsync(requestMessage);
// Just as an example I'm turning the response into a string here
string responseAsString = await response.Content.ReadAsStringAsync();

DotNetOpenOAuth Content-type

I am tearing my the remainings of my hair off trying to solve an issue with DotNetOpenOAuth. Below are the details of the problem.
Consumer = new DesktopConsumer(xeroProviderDescription, _tokenManager);
var endPoint = new MessageReceivingEndpoint(apiEndPoint, HttpDeliveryMethods.PostRequest | HttpDeliveryMethods.AuthorizationHeaderRequest);
var request = Consumer.PrepareAuthorizedRequest(endPoint, accessToken);
var content = Encoding.UTF8.GetBytes(payload);
request.ContentType = "application/json";
request.ContentLength = content.Length;
This works perfectly fine, the server accepts the request and replies. Now, I want to switch to using xml to talk to the remote service (this is their prefered format over json) So I changed all the code into sending XML data instead of json and changed the content-type to application/x-www-form-urlencoded as per the web service provider documentation. The problem now is that the service is returning 401 unauthorized request - Reason: invalid signature whenever application/x-www-form-urlencoded is used
Questions:
Is the Content-Type taken into account when generating the oauth signature (I looked into the DotNetOpenOAuth source code with no luck)?
Anyone has ever encountered this issue and resolved it?

BrokerProperties REST header values not showing up in .NET client code

I'm writing two small pieces of C# code. The first is for a client-side Portable Class Library. All it does is send messages to an Azure Service Bus topic via the Azure Service Bus REST API, using HttpClient.
I populate the BrokerProperties header on the REST call with valid JSON, and I expect that on the server side, when I receive the message through a subscription, that I'll get my instance of BrokeredMessage.Properties populated with the values I sent from the client.
The one problem I've had on this side is that the documentation says to set Content-Type to application/atom+xml;type=entry;charset=utf-8, but even when I do I get application/json; charset=utf-8, so I'm just using application/json.
With that aside, as far as I can tell, this does what it's supposed to do. It creates the client and the request message, sets the headers, and sends the message. I get a 201 Created every time. Here's all of it:
private async static void SendServiceBusMessage(Command command)
{
// Create the HttpClient and HttpRequestMessage objects
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, topicUri);
// Add the authorization header (CreateAuthToken does the SHA256 stuff)
request.Headers.Add("Authorization", CreateAuthToken(topicUri, authSasKeyName, authSasKey));
// Add the content (command is a normal POCO)
// I've tried application/atom+xml;type=entry;charset=utf-8, always see application/json in the request
request.Content = new StringContent(JsonConvert.SerializeObject(command), Encoding.UTF8, "application/json");
// Add the command name and SessionId as BrokeredMessage properties
var brokeredMessageProperties = new Dictionary<string, string>();
brokeredMessageProperties.Add("CommandName", command.GetType().Name);
brokeredMessageProperties.Add("SessionId", Guid.NewGuid().ToString());
// Add the BrokerProperties header to the request
request.Content.Headers.Add("BrokerProperties", JsonConvert.SerializeObject(brokeredMessageProperties));
// I've also tried adding it directly to the request, nothing seems different
// request.Headers.Add("BrokerProperties", JsonConvert.SerializeObject(brokeredMessageProperties));
// Send it
var response = await client.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
// Do some error-handling
}
}
and here's an example of the HTTP request it sends. Compare it to the example at the bottom of Send Message documentation... aside from the Content-Type, it looks (functionally) identical to me.
POST https://myawesomesbnamespace.servicebus.windows.net/commands/messages HTTP/1.1
Authorization: SharedAccessSignature sr=https%3A%2F%2Fmyawesomesbnamespace.servicebus.windows.net%2Fcommands%2Fmessages&sig=SomeValidAuthStuffHere
Content-Type: application/json; charset=utf-8
BrokerProperties: {"CommandName":"CreateJob_V1","SessionId":"94932660-54e9-4867-a020-883a9bb79fa1"}
Host: myawesomesbnamespace.servicebus.windows.net
Content-Length: 133
Expect: 100-continue
Connection: Keep-Alive
{"JobId":"6b76e7e6-9499-4809-b762-54c03856d5a3","Name":"Awesome New Job Name","CorrelationId":"47fc77d9-9470-4d65-aa7d-690b65a7dc4f"}
However, when I receive the message on the server, the .Properties are empty. This is annoying.
The server code looks like this. It just gets a batch of messages and does a foreach loop.
private async Task ProcessCommandMessages()
{
List<BrokeredMessage> commandMessages = (await commandsSubscriptionClient.ReceiveBatchAsync(serviceBusMessageBatchSize, TimeSpan.FromMilliseconds(waitTime_ms))).ToList();
foreach (BrokeredMessage commandMessage in commandMessages)
{
// commandMessage.Properties should have CommandName and SessionId,
// like I sent from the client, but it's empty
// that's not good
if (commandMessage.Properties.ContainsKey("CommandName"))
{
string commandName = commandMessage.Properties["CommandName"] as string;
// Do some stuff
}
else
{
// This is bad, log an error
}
}
}
So, I'm a bit stuck. Can anyone spot something I'm doing wrong here? Maybe it's the Content-Type problem and there's a way around it?
Thanks!
Scott
Seattle, WA, USA
OK, finally getting back to this. What I misunderstood (and I'd argue the documentation isn't clear about) is that arbitrary properties cannot be passed through the BrokerProperties header. Only named properties from the BrokeredMessage class (like SessionId, Label, etc.) will come through Service Bus to the server.
For properties to show up in BrokeredMessage.Properties, they have to be passed as custom headers on the request. So, in my case,
request.Headers.Add("CommandName", command.GetType().Name);
gets the CommandName property to show up on the server after the message is passed through Service Bus.
And to pass the SessionId value, I'll still want to pass it through BrokerProperties header.

Categories

Resources