HTTPClient POST works on postman but not inside a c# application - c#

I am trying to use a Rest API from outside my company's domain. My problem is when I run the POST request within Postman or an Angular application it works fine. But when I send the same payload within a winforms c# application, I get Access Forbidden. You have browsed from an unrecognized IP address. The proxy therefore denied access to this site.
I thought the problem was with the payload itself, so I copied the same JSON string, sent it via postman and It worked. So I thought perhaps the issue is with the server itself, so I ran other GET requests to the same server and they worked. I tried sending an empty string to the POST request and it worked, tried an empty object and get FORBIDDEN REQUEST. The same code, I ran it from my personal computer and it worked.
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", sToken);
StringContent sRequestContent = new StringContent(requestPayload, Encoding.UTF8, "application/json");sRequestContent).Result;
var result = client.PostAsync(new Uri(sUrl), sRequestContent).Result;
return result.Content.ReadAsStringAsync().Result;
PS:
requestPayload is a JSON string.

Related

C# HttpClient authorization header removed after send to server

I wanna send request to external API through the HttpClient from my own API in c#.
I am using dot net 5 and basic authentication.
Here is my code:
var client = new HttpClient
{
BaseAddress = new Uri(baseUrl)
};
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Put, "apiUrl");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var param = JsonConvert.SerializeObject(new
{
param1="",
param2=""
});
requestMessage.Content = new StringContent(param, Encoding.UTF8, "application/json");
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(Encoding.ASCII.GetBytes($"{user}:{pass}")));
HttpResponseMessage response = await client.SendAsync(requestMessage);
Usually, I send http request like this.
but now I have some problem.
After line HttpResponseMessage response = await client.SendAsync(requestMessage); authorization header removed from my request header and I got UnAuthorized http error.
I know that when redirection occurs, authorization header removed for security reason. Also I'm not sure about redirect in external API.
I add the HttpClientHandler with AllowAutoRedirect = false to my HttpClient
var handler = new HttpClientHandler()
{
AllowAutoRedirect = false,
};
var client = new HttpClient (handler)
{
BaseAddress = new Uri(baseUrl)
};
Now I got Redirect error 301(Permanently moved).
I decided to test the code in Postman. By default, when I call API in Postman, I got http error 405 method not allowed and error detail like this:
{
"detail": "Method "GET" not allowed."}
External API method is PUT. but here I got GET Error.
I tried many options in postman and finally I find the option in Postman:
When I toggle it on, external API work's properly.
Also I test it with Insomnia and it's work properly.
Does it related to my code or dot net 5 or what other thing in my code or it's related to external API?
If it's related to my code, How can I solve the error?
If error related to external API, why Postman and Insomnia response is ok?
External API has Core Policy for specific domain and I send request from other domain.
All I Know is that the CORS policy applied in browser. not in Postman, Insomnia or C# Code.
What about CORS? Does it related to CORS? if Yes, what shall I do?
I will be grateful for your answer.
Update
I detect WWW-Authenticate: JWT realm="api" in the response header.
What exactly is it? and what shall I do?
I find out the problem. It's really Ridiculous.
When I use URL like www.abc.com/api/something the request gets 301 error and postman sends another request like www.abc.com/api/something/. The difference is just / at the end of request.
I tried new URL in postman and first request got ok.
Also I tried URL in my C# code and again its ok.
But i could not understand why.
Thanks a lot dear #pharaz-fadaei
You are right about the removal of authorization headers after redirects. But keep in mind that this behavior is part of the design of the HttpClient in C#. Postman and Insomnia may have different mechanisms to send the authorization headers on each consecutive request that is caused by redirects. The option that you enabled in Postman will make it use the original HTTP method you specified (PUT) as the HTTP method to send further requests based on the redirect messages (Postman uses GET method by default on requests instructed by redirect messages).
The fact that you see a 301 shows that a redirection is required. You can check Location header value in response.Headers to see the real location and send your requests with the authorization headers to that endpoint directly. If I were you I wouldn't use the new location directly because the original endpoint is what you were given by the authors of the API. Instead I would programmatically send the request to the original endpoint and resend the request on 301 codes to the new Location (use PUT method due to the behavior of Postman) until you get the result. This answer can give you some ideas: https://stackoverflow.com/a/42566541/1539231
Since you see WWW-Authenticate: JWT realm="api" header, the external API is required a JWT token authentication, not basic authentication. I think first you might need to check external api's documentation.

Calling Azure Function app works in console but not in xamarin forms

So I created a function which is a Get request. All the function does is retrieves some data from an SQL database and returns it.
I call this function in a console app, just to test it, and all is working as it should.
I then copy the code and paste it into my xamarin.forms app for android.
When I run it it immediately gives me a 404 Not found response.
Any idea why it's not working in the xamarin app but is working in the console app?
using (var client = new HttpClient())
using (var request = new HttpRequestMessage(HttpMethod.Get, "http://{MySite}.azurewebsites.net/api/{myfunction}/"))
using (var httpContent = CreateHttpContent(new DiaryDate() { Date = DateTime.Today }))
{
request.Content = httpContent;
using (var response = await client
.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken)
.ConfigureAwait(false))
{
if (response.IsSuccessStatusCode)
{
// do something
}
}
}
CreateHttpContent just converts the given object to JSON.
Update the URL to https scheme (https://{MySite}.azurewebsites.net/api/{myfunction}/). Firstly, there is no reason for choosing non-secure channel. Azure Function side won't require any change to use https. Secondly, as pointed out in the other answer, there is restriction in client side for http which would require tweak to unblock.
UPDATE: In this particular call, you are using Http GET, but sending a request content (json of DiaryDate object). So, it will send that via query string in the the URL. Though I am not yet sure how it's working in console app (might be something to do with how it's handled in Xamarin/Mono http handler v/s that of .net core in console app in GET request), but it should be POST surely. Can you change HttpMethod.Get to HttpMethod.Post in the line where you are creating HttpRequestMessage.

Using GET request causes bot dialog to fail

I've connected my bot application to the direct line API which is published with Azure. I am currently testing the application with a command line client application, the bot framework emulator, and the dev.botframework.com homepage for my bot.
Everything works correctly until I attempt to submit a GET request to a REST API. I've tested the GET API request in a separate project and it works correctly and the GET request worked prior to implementing the direct line channel. Is there anything I need to be aware of when making http requests with the direct line on the bot side?
Code in question
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", headerParam);
var response = client.GetAsync(new Uri("someUrl.com/api/v1/auth")).Result;
string content = response.Content.ReadAsStringAsync().Result;
var jo = JObject.Parse(content);
this.token = jo["Result"]["Token"].ToString();
}
await context.PostAsync(this.token);
the line that actually causes the failure is
var response = client.GetAsync(new Uri("someUrl.com/api/v1/auth")).Result;
Also is there an easier way to debug a project when it's published to azure and running direct line API?
System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: An attempt was made to access a socket in a way forbidden by its access permissions ipaddress
I have tried to invoke my custom REST API within my bot application back-end, then I could leverage Remote debugging web apps to retrieve the result from my bot application hosted on Azure web app as follows:
After searching for the related issue, I found that there be limitation for the number of sockets of your current app service plan when creating the new outgoing connections. You could try to scale up your App Service plan or create a new web app to isolate this issue. For more details, you could refer to this similar issue and this blog.

Error 406 Not Acceptable JSON

http://www.jfrog.com/confluence/display/RTF/Artifactory+REST+API#ArtifactoryRESTAPI-CreateorReplaceRepositoryConfiguration
I am using the Create or Replace Repository Configuration call. However I am getting a 406 Error: Not Acceptable. Other PUT calls are working but do not return JSON. I believe JSON is the source of the error but have not been able to resolve or prove this.
I have added the code as below
RestClient Client = new RestClient(uriString);
RestRequest Request = new RestRequest(requestType);
Request.AddHeader("Authorization", "Basic " + credentials);
Request.AddHeader("Accept", "application/json");
I've seen threads where adding the header to accept JSON resolves the error but this has not worked for me.
A 406 HTTP status means that if a web server detects that the data it wants to return is not acceptable to the client, it returns a header containing the 406 error code.
The client can define the characteristics of the data it will accept back from the web server by using the accept headers.
In this case you declare the you would like to accept application/json:
Request.AddHeader("Accept", "application/json");
however the REST API method you are invoking is returning text/plain.
You should change the code to accept text/plain:
Request.AddHeader("Accept", "text/plain");
Wanted to add this for for future users stuck like me. I was having the same issue and tried the request with Postman and saw that the Content-Type was "application/hal+json" I was trying it with application/json without luck.
So running a test in postman I was able to figure out what the server needed exactly.
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/hal+json"));
I faced the same 406 Error: Not Acceptable when trying to get JSON on another site. In my case I could see correct JSON when typed url in my browser address field. But downloading it from the same url via my C# code have been producing 406 Error.
None of the answers in this topic solved my problem directly. But at least they pointed out to me that's the point is HTTP headers.
So I googled that page:
https://www.whatismybrowser.com/detect/what-http-headers-is-my-browser-sending
and added all browser headers to my code, and voila! It started to work.
In my case it was enough to fill some data in user-agent header.
First, the Accept header states what the client is ready to get back, not what the client sends.
The header that states what the client sends is Content-Type.
Also, this method does not accept application/json. As clearly stated in the docs, it accepts one of the following:
application/vnd.org.jfrog.artifactory.repositories.LocalRepositoryConfiguration+json
application/vnd.org.jfrog.artifactory.repositories.RemoteRepositoryConfiguration+json
application/vnd.org.jfrog.artifactory.repositories.VirtualRepositoryConfiguration+json

How to use RestRequest/RestResponse when the web service produces multipart form data in C#?

I have a web service in a RESTful web server (java) which consumes media of type APPLICATION_FORM_URLENCODED and produces media of type MULTIPART_FORM_DATA. Now I'm working on a REST client (C#) and trying to use this web service. I'm using RestSharp as the REST client. My code goes as follows:
RestRequest request = new RestRequest("getDataFileChunkIS", Method.POST);
request.AddParameter("sessionId", sessionId);
request.AddParameter("dataFileId", dataFileId);
request.AddParameter("offset", offset);
request.AddParameter("chunkSize", chunkSize);
request.AddParameter("checksumFlag", checksumFlag);
RestClient client = new RestClient(url);
RestResponse response = (RestResponse)client.Execute(request);
But in this response I'm getting HTTP Status 406 - Not Acceptable. It says "The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers." Maybe I'm doing it in a wrong way. So my question is that how can I execute this request whose response will contain MULTIPART_FORM_DATA ?
1) how can I execute this request whose response will contain MULTIPART_FORM_DATA?
request.AddHeader("Accept", "multipart/form-data")
2) how can I read this response header(contains JSON) using RestClient?
See answers to this question. Particularly the third one, which shows how to do it just with .NET 4.5 libraries.
You may need to implement IDeserializer to get access to the raw HttpResponse for consumption.

Categories