Setting REQUEST header Http Client vb.net - vb.net

Consider the following VB code:
Public Async Function someFunction(ByVal url As String, Optional ByVal methodPost As Boolean = False, Optional ByVal postContent As HttpContent = Nothing) As Threading.Tasks.Task(Of String)
Using client = New HttpClient
client.DefaultRequestHeaders.Authorization = makeAuthenticationHeader()
If methodPost Then
client.DefaultRequestHeaders.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json"))
Dim Response = Await client.PostAsync(url, postContent)
Dim content As String = Await Response.Content.ReadAsStringAsync
Return content
Else
Return Await client.GetStringAsync(url)
End If
End Using
End Function
I want to set the request content type to application/json as well as the response content type to application/json.
If I add the following line of code:
client.DefaultRequestHeaders.Add("content-type", "application/json") then the system throws an exception Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects..
I've searched all over google for a way to set the requests header to JSON. Using fiddler (on the server) I can see that the request is sent as plain/text.
POST **URL REMOVED FOR SAFETY REASONS** HTTP/1.1
Authorization: Basic **HASHED AUTH DETAILS - REMOVED FOR SAFETY REASONS**
Accept: application/json
Content-Type: text/plain; charset=utf-8
Host: **HOST REMOVED FOR SAFETY REASONS**
Content-Length: 1532
Expect: 100-continue
Connection: Keep-Alive
Content-Type: text/plain; charset=utf-8 This is where I am having an issue. This needs to be set to a content type for JSON as the body of the request is JSON. How do I set this content-type to JSON in vb.net Code.

I found a solution, I don't know if it is the correct solution or if there is a better solution out there.
Basically you need to set the content-type header on the actual content that you are sending and not on the HTTP Client.
So basically adding content.Headers.ContentType = New MediaTypeWithQualityHeaderValue("application/json") to your code should set the REQUEST's content-type to JSON as well.
Public Async Function someDifferentFunction() As Threading.Tasks.Task(Of String)
Dim url As String = "http://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Dim content As HttpContent = New StringContent(txtRequestBody.Text)
content.Headers.ContentType = New MediaTypeWithQualityHeaderValue("application/json")
Return Await someFunction(url, True, content)
End Function

Related

How to corectly set the ContentType property in HttpWebRequest (or how to fix the missing Content-Type header)

I thought I'd share something that took me some time to figure out:
I wrote a simple Post method using HttpWebRequest class.
In HttpWebRequest you can't use HttpWebRequest.Headers collection to set your desired headers when there is a dedicated property for it - you must use that dedicated property. ContentType is one of them. So I created my HttpWebRequest like this:
HttpWebRequest httpWebRequest = (HttpWebRequest)webRequest;
httpWebRequest.Method = "POST";
httpWebRequest.KeepAlive = false;
httpWebRequest.ServicePoint.Expect100Continue = false;
httpWebRequest.ContentType = "application/json";
somewhere below I set the body of my request like this:
using (StreamWriter streamWriter = new StreamWriter(streamWebRequest))
{
streamWriter.Write(sJson);
}
and posted the request using:
WebResponse webResponse = httpWebRequest.GetResponse();
But I kept getting a "400 - Bad Request" error, while the same request worked from Postman. After analyzing the request with Fiddler I found that when I send the request from my app, the Content-Type: application/json header is missing. All the other headers were present, except for Content-Type. I thought I'm setting it wrong, so I googled but didn't find a good answer. After much experimentation I found, that if I move the line:
httpWebRequest.ContentType = "application/json"
after this block:
using (StreamWriter streamWriter = new StreamWriter(streamWebRequest))
{
streamWriter.Write(sJson);
}
then the httpWebRequest.ContentType = "application/json" header finally appears in the request. So, for HttpWebRequest make sure you always set your HttpWebRequest's body/content first, before you set the ContentType property.
Hope it helps
My question above already has the answer, but to mark it as "Answered" I had to add this comment:
Make sure you always set your HttpWebRequest's body/content first, before you set the ContentType property.This way the "Content-Type" header will appear in the request.

PostAsJsonAsync posts null

I am trying to post an object using PostAsJsonAsync, but it is always null at the receiving API. The calling code is here:
public async Task UploadDocument(FileDto model)
{
var response = await _httpClient.PostAsJsonAsync("file/UploadDocument", model);
response.EnsureSuccessStatusCode();
}
The signature of the receiving code is here:
[HttpPost]
[Route("UploadDocument")]
public async Task<IHttpActionResult> UploadDocument(FileDto document)
FileDto is identical in both projects and only contains one string property "FileName"
The problem is that the document is always null.
I can use PostAsync which works fine:
public async Task UploadDocument(FileDto model)
{
string inputJson = Newtonsoft.Json.JsonConvert.SerializeObject(model);
HttpContent inputContent = new StringContent(inputJson, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync("file/UploadDocument", inputContent);
response.EnsureSuccessStatusCode();
}
Looking at Fiddler, with the first (not working) example, the request looks like this:
POST http://localhost:59322/api/file/UploadDocument HTTP/1.1
Accept: application/json
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Host: localhost:59322
28
{"FileName":"File-0000004157.jpg"}
0
The second (working) example looks like this in Fiddler:
POST http://localhost:59322/api/file/UploadDocument HTTP/1.1
Accept: application/json
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Host: localhost:59322
{"FileName":"File-0000004157.jpg"}
The first example appears to have added extra text - see the "28" and "0".
Where is this text coming from. I can just go with PostAsync, but it seems a shame to add the extra code when PostAsJsonAsync does it for you.
Anybody have any ideas?
You need to return IActionResult instead of IHttpActionResult in asp.net core
[HttpPost]
[Route("UploadDocument")]
public async Task<IActionResult> UploadDocument(FileDto document)
{
return Ok(document);
}
https://learn.microsoft.com/en-us/aspnet/core/migration/webapi?view=aspnetcore-3.0
ASP.NET Core Web Api Error for IhttpActionResult
There seems to be an issue with PostAsJsonAsync in .net core : It returns a content-length of 0 causing the receiving ends to ignore the declared empty body.
https://github.com/aspnet/AspNetWebStack/issues/252
HttpClient PostAsJsonAsync behaving different in .NET Core and Classic .NET
The workaround is to use... PostAsync

how to add 'Content-Type' header in (HTTP GET) Rest request header collection using HttpClient?

I am using HttpClient for rest service . At at one point I have a problem when I try to add "Content-Type" in my 'Get' request header .
I know "Content-Type" is suitable for content send in request body part But It's my need i have to send "Content-Type" with request header part.
I also try to remove "Content-Type" header from Invalid Header list of HttpRequestHeaders
I find link How do you set the Content-Type header for an HttpClient request?
Dim field = GetType(System.Net.Http.Headers.HttpRequestHeaders).GetField("invalidHeaders", System.Reflection.BindingFlags.NonPublic Or System.Reflection.BindingFlags.[Static])
If field IsNot Nothing Then
Dim invalidFields = DirectCast(field.GetValue(Nothing), HashSet(Of String))
invalidFields.Remove("Content-Type")
End If
But my issue not resolved I have exception
InnerException:
Message=The 'content-type' header must be modified using the appropriate property or method.
StackTrace:
at System.Net.WebHeaderCollection.ThrowOnRestrictedHeader(String headerName)
at System.Net.WebHeaderCollection.Add(String name, String value)
at System.Net.Http.HttpClientHandler.SetRequestHeaders(HttpWebRequest webRequest, HttpRequestMessage request)
at System.Net.Http.HttpClientHandler.CreateAndPrepareWebRequest(HttpRequestMessage request)
at System.Net.Http.HttpClientHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
InnerException:
I find some tools like Postman or SoupUI allow this .
Please help me to find some solution .
Thanks
HttpWebRequest may come to your rescue.
private static string CallService(string url)
{
WebRequest req = WebRequest.Create(url);
req.Method = "GET";
String json;
req.ContentType = "application/json; charset=utf-8";
var resp = req.GetResponse();
using (varstream = resp.GetResponseStream())
{
var re = new StreamReader(stream);
json = re.ReadToEnd();
}
return json;
}
}
Async implementation of this can be found from Getting the Response of a Asynchronous HttpWebRequest

How to set Content-Type header in a http get response using C#'s HttpClient?

I am having problems in retrieving the contents of a http get request in the proper charset.
I tried several pieces of code, such as the following:
HttpClient h = new HttpClient();
//Content-Type: text/html; charset=UTF-8
//p.s. contents are in hebrew.
var resp = h.GetAsync("http://www.wnf.co.il");
var content = resp.Result.Content;
//remove the default Content-Type header
content.Headers.Remove("Content-Type");
content.Headers.Add("Content-Type", "text/html; charset=utf-8");
var res = content.ReadAsStringAsync();
var s = res.Result;
Console.WriteLine(s);
which still does not help, I still get the content in wrong encoding.
This post clarifies that setting the header's request headers charset will not help, it's the response's one that needs to be set. (Besides, you will get an error in trying to add
header "Content-Type" to a request Header.)
But I still could not end up with working retrieval of the content in the proper charset (utf-8).
What am I missing ?
I have been doing similar stuff with hebrew sites for a while, in comparing the response's header in Fiddler from this site and others where I do not have this problem - the only difference I see is indeed this Content-Type header in the response.
The issue is probably due to this bug:
https://connect.microsoft.com/VisualStudio/feedback/details/790174/system-net-http-httpcontent-readasstringasync-does-not-handle-imperfect-content-type-headers
The work-around is to get the response as a byte array and encode it yourself:
var bytes = await content.ReadAsByteArrayAsync();
var s = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
As a side-note, is there a reason you're using .Result instead of await? You are blocking the current thread unnecessarily and setting yourself up for deadlocks.

VBA ServerXMLHTTP proxy is fine with https but fails on http

I'm trying to write a macro to do some querying from the web to update an Access database. For some reason, VBA refuses to play friendly with http, but is totally content to do https.
Here's my requesting function:
Function httpRequest(ByVal url As String, useProxy As Boolean) As String
Dim response As String
Dim proxy As String
Dim xhr As Object
'Make HTTP requester object
Set xhr = CreateObject("MSXML2.ServerXMLHTTP.6.0")
If useProxy Then
If Left(url, 5) = "https" Then
proxy = "proxyb1secure:8443"
Else
proxy = "proxyb1:8080"
End If
xhr.setProxy 2, proxy
End If
xhr.Open "GET", url, False
'send the request. THIS LINE TIMES OUT ON HTTP
xhr.Send
'fetch the whole page
response = xhr.responseText
'clean up
Set xhr = Nothing
'return
httpRequest = response
End Function
And my testing function:
Function testProxy()
'This one works
MsgBox (httpRequest("https://www.bing.com/search?q=stackoverflow", True))
'This one doesn't.
MsgBox (httpRequest("http://www.bing.com/search?q=stackoverflow", True))
End Function
I'm certain I'm going after the right name and port, because I've tested the same thing via Java, and it's content to do both flavors (i.e. everything works perfectly in the following code).
public static void main(String[] args) throws Exception {
URL url = new URL("http://www.bing.com/search?q=stackoverflow");
HttpURLConnection con = (HttpURLConnection) url.openConnection(getProxyForURL(url));
System.out.println(con.getResponseCode() + " " + con.getResponseMessage());
InputStream is = con.getInputStream();
int c;
StringBuilder sb = new StringBuilder();
while ((c = is.read()) != -1) {
sb.append((char) c);
}
String page = sb.toString();
System.out.println(page);
}
public static Proxy getProxyForURL(URL url) {
if (url.getProtocol().equals("https")) {
return new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxyb1secure", 8443));
} else {
return new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxyb1", 8080));
}
}
What trickery of VBA am I missing?
Mystery solved. Turns out this is a security feature revolving around the user agent (of all things...).
Java used these HTTP headers (which were successful):
GET http://www.bing.com/search?q=stackoverflow HTTP/1.1
Accept: */*
Accept-Language: en-us
Proxy-Connection: Keep-Alive
User-Agent: Java/1.7.0_79
Host: www.bing.com
and Access sent these (which were unsuccessful):
GET http://www.bing.com/search?q=stackoverflow HTTP/1.1
Accept: */*
Accept-Language: en-us
User-Agent: Mozilla/4.0 (compatible; Win32; WinHttp.WinHttpRequest.5)
Proxy-Connection: Keep-Alive
Host: www.bing.com
by simply adding a
xhr.setRequestHeader "User-Agent", "PayMeNoAttention"
it magically goes through. And to confirm the theory, adding Access' user-agent to Java caused it to fail. So. That's definitely what's up.
This is likely an attempt by our brilliant network techs to block macro viruses from contacting malicious sites.