API call returns 408 (Your POST request is not being received quickly enough. Please retry) but works fine with Postman and ajax - asp.net

Calling an external API from asp.net core 2.2 with framework 4.6.1 using HttpClient always returns 408 with an error message Your POST request is not being received quickly enough. Please retry but same code works fine with pure asp.net 2.2. The external API also works fine when I use Postman or ajax.
Here is the API call -
using (var client = _httpClientFactory.CreateClient())
{
client.BaseAddress = new Uri("https://example.com/authenticate");
var response = await client.PostAsync(string.Empty, new JsonContent(data));
var content = await response.Content.ReadAsStringAsync();
return StatusCode((int)response.StatusCode, content);
}

Related

Connection closed from Facebook using http requests from ASP.net

I'm trying to make some GETs to the Facebook rest api from an ASP.net core application, but I get every time an exception because the remote host closed the connection. I tried like fourty different solutions that I found in similar questions but none of them worked. I changed the security protocol to Tls 1.2 but still got the same issue; I also tried using web client instead of http client. Then I tought it might have been the proxy of my office but cUrl worked fine; using postman I didn't get any error (even with tsl set to 1.0).
Another attempt was to try changing the keep-alive duration to avoid time-outs.
Here's the code with the HttpClient:
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
using (var httpClient = new HttpClient()){
httpClient.DefaultRequestHeaders.Add("Connection", "Keep-Alive");
httpClient.DefaultRequestHeaders.Add("Keep-Alive", "3600");
var request = new HttpRequestMessage(HttpMethod.Get,
"https://graph.facebook.com/v10.0/me?fields=id%2Cemail%2Cfirst_name%2Clast_name&access_token=" + socialLoginModel.accessToken);
request.Headers.Add("Accept", "application/json");
request.Headers.Add("User-Agent", "BriQ");
var response = await httpClient.SendAsync(request);
}
And here's the code with the WebClient:
using(var wb = new WebClient()){
var response = wb.DownloadString("https://graph.facebook.com/v10.0/me?fields=id%2Cemail%2Cfirst_name%2Clast_name&access_token=" + socialLoginModel.accessToken);
}
I'm completely out of ideas. Maybe it's something really stupid that's causing the exception but I can't figure it out alone
I'm not sure about which exception that you exactly got.
But as far as I know, if you're using .NET Core and the problem is caused by the SSL/TLS handshake failure error, then, unfortunately, setting the ServicePointManager may not work...
Because the ServicePointManager only affects the HttpWebRequest which is the default implementation of HttpClient on .NET Framework. Starting with .NET Core 2.1, the SocketsHttpHandler provides the implementation used by HttpClient.
Hence, I suppose the way to fix the issue is handling the SocketsHttpHandler:
using (var handler = new SocketsHttpHandler())
{
handler.SslOptions = new SslClientAuthenticationOptions{EnabledSslProtocols = SslProtocols.Tls12};
using (var httpClient = new HttpClient(handler))
{
// your code
}
}
Alternatively, if you prefer HttpClientHandler, you could do in this way:
using (var handler = new HttpClientHandler())
{
httpClientHandler.SslProtocols = System.Security.Authentication.SslProtocols.Tls12;
using (var httpClient = new HttpClient(handler))
{
// your code
}
}
Refs:
How to use TLS 1.2 in ASP.NET Core 2.0
HttpClient Class

Sitecore hosted on IIS, API returned 404 but has content

I have a Sitecore site and I'm trying to make API calls from a controller. For some reason API always returns the 404 not found, but it also executes the code correctly and returns the content. I tried to call the same API endpoint via Postman and returned the 200 code with content.
Here's my RouteConfig:
routes.MapRoute("Feature.DataIntegration.Api", "api/dataintegration/{action}",
new
{
controller = "DataIntegration"
});
Here's my API (I tried to use [HttpGet] attribute, but it didn't work):
public string test1()
{
return "Asdas";
}
This is my RestSharp code:
var url = "http://tdev.xxx.cd.local/api/dataintegration/test1";
var client = new RestClient(url);
var request = new RestRequest();
IRestResponse response = client.Execute(request);
This is Postman's return:
This is when the result from RestSharp (I also tried with httpclient, the same result):
I have tried to disable my firewall, but doesn't work neither.
How can I fix the 404 not found? If I don't fix this, does this affect the API once deployed to a real server?

Using an asp web api in wpf

So i have got a simple question, when using our cms we can attach a driver as an executable.
The driver we want to make is an httpreceiver or just an api endpoint. SO i tought lets use asp.net web api for it -> using version .net 4.6.1. altough asp.net application requires a webserver and is not an executable, But i read on google you can use it inside a wpf application since our cms is wpf in the first place.
So my question is is there a way i can use my mvc web api project inside a wpf application? and if not what would be the best bet to have an httpreceiver or httppost receiver into an executable?
Main reason is we want to send httppost requests to the server as a desktop application. I know it's complicated but thats how it needs to be as far as I know.
In the case where asp is not an option, what the best way to make a postreqst/ httpreceiver as a desktop application?
EDit:
the resource guide from microsoft beneath was perfectly however i still have a question:
string baseAddress = "http://localhost:9000/";
// Start OWIN host
using (WebApp.Start<Startup>(url: baseAddress))
{
// Create HttpClient and make a request to api/values
HttpClient client = new HttpClient();
string username = "test".ToUpper().Trim();
string password = "test123";
//Mock data
var body = new PostTemplate1();
body.Description = "test";
body.StateDesc = "httpdriver/username";
body.TimeStamp = DateTime.Now;
body.Message = "This is a post test";
var json = JsonConvert.SerializeObject(body);
var data = new StringContent(json, Encoding.UTF8, "application/json");
var authToken = Encoding.ASCII.GetBytes($"{username}:{password}");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(authToken));
var response = await client.PostAsync(baseAddress + #"api/Post", data);
var result = response.StatusCode;
}
As the guide says you post to url with port 9000
is there a possibility to use another port and use https?
if yes where to manage certificates for handling https?

WCF service act as proxy for external web service

I'm working on developing proxy WCF service. So tasks that I have to achieve as part of this assignment are:
I have to capture headers and content from an incoming request (from
a web browser).
Construct a web request for external web service with headers and
content from incoming request.
Execute web request.
Capture headers/cookies/content form the Response of external web
service.
Construct response, add headers/cookies and send response back to
browser.
I'm able to manage 1, 2 , 3 and 4 with help of web and stackoverflow. But not find any solution for task 5.
Questions:
Response message from external web service is a json. How to send the same message in json format to web browser?
Response from external web service has 'set-cookie' header. How to add this to web browser response?
I'm new to WCF and Web Service world. Using System.Net.Http.HttpClient to make a call to external web service. Open to change it to any other client library to achieve tasks 1 to 5.
Code blocks:
IService1.cs
[OperationContract]
[WebInvoke(Method = "POST",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.WrappedRequest,
UriTemplate = "client/api")]
string ProxyAPI(Stream inp);
Service1.cs
public string ProxyAPI(Stream contentStream)
{
// Task 1: Capture Headers and content
// Task 2: Construct web request with headers and content from incoming request
HttpClient proxyClient = new HttpClient();
Uri extWSuri = new Uri("http://router.sdc.com:8090/service/api");
proxyClient.BaseAddress = extWSuri;
// get input reqquest headers and add to httpclient onject
WebOperationContext current = WebOperationContext.Current;
WebHeaderCollection headers = current.IncomingRequest.Headers;
string[] headerKeys = headers.AllKeys;
foreach (string keyStr in headerKeys)
{
if (keyStr.ToLower().Equals("host"))
{
proxyClient.DefaultRequestHeaders.Add(keyStr, "router.simplifydc.com:8080");
}
else if (!keyStr.ToLower().StartsWith("cont"))
{
proxyClient.DefaultRequestHeaders.Add(keyStr, headers.GetValues(keyStr));
}
}
// get input content data
StreamReader reader = new StreamReader(contentStream);
string contentData = reader.ReadToEnd();
reader.Close();
// create content for httpclient request
StringContent contentRequest = new StringContent(contentData, System.Text.Encoding.UTF8, "application/x-www-form-urlencoded");
// Task 3: execute web request
Task<HttpResponseMessage> responseTask = proxyClient.PostAsync(extWSuri, contentRequest);
responseTask.Wait();
// Task 4: Capture headers/cookies/contnet from web response
HttpResponseMessage response = responseTask.Result;
HttpResponseHeaders resHeaders = response.Headers;
Task<string> contentTask = response.Content.ReadAsStringAsync();
contentTask.Wait();
string responseMsg = contentTask.Result;
// Task 5: construct response for incoming web browser request
// ?????????????
return responseMsg;
}
If I get it right, the client application for your WCF service is a web browser. This means that it expects an HTML document as a response right? In this case, I would suggest to avoid using a WCF service.
Why don't you use an ASP.NET page which forms the HTML to return? In your ASP.NET code behind, you could execute the 4 four steps you describe. In your 5th step, you would adjust the HTML to contain the data you got in the previous steps from the external web service.
You could always construct the HTML response using the WCF service, but I cannot see why. You could use and HTML DOM parser (like this to construct the HTML response programmatically, but this would not be my first approach.
If your page requires pure data and not HTML, your WCF service could return data in JSON format. As you can see, JSON is a simple string which could be very easy to construct. It depends on the data you want to return, but it could be very easy implemented either manually, or using some specific library like Json.NET. Then your UI application would parse JSON and display data accordingly.
Hope I helped!

Do I need to investigate HTTP 401 cached by Fiddler during the HttpWebRequest post to ASP.NET WebApi server

I am totally new to WebApi and WebRequests and other things.
After hours of googling, finally, I managed to do POST using C# and HttpWebRequest.
When I do HttpWebRequest in debug mode using Visual Studio I do not get any exceptions.
My app work as I accept , I get data to webApi server and also get back data.
To be sure how my app communicate with WebApi server I start Fiddler Web Debugger.
During the POST to WebApi, Fiddler chace 401 errors
{"Message":"Authorization has been denied for this request."}
Steping step by step in debuger I fund that following lines of code doing 401 error
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
wr.Credentials = new NetworkCredential(username, password);
wr.Method = "POST";
wr.ContentType = "application/json";
byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(body);
wr.ContentLength = byteArray.Length;
using (System.IO.Stream dataStream = wr.GetRequestStream())
{
dataStream.Write(byteArray, 0, byteArray.Length); //After this line of code Fidler Chace HTTP 401
}
Later in code when I do wr.GetResponse() I do get status 200OK.
My questions are :
Do I need to redesign my code to avoid this error in Fiddler ?
Is there other methods to fill HttpWebRequest whit jsonSting beside using GetRequestStream() ?
If your service is enabled with Windows Authentcation, then in Fiddler, you can select the option to automatically authenticate using your logged on credentials by going here:
Composer tab -> Options tab -> Automatically Authenticate
Also, why not use HttpClient from System.Net.Http?...It has a much better and easy programming model...example:
HttpClientHandler handler = new HttpClientHandler();
handler.UseDefaultCredentials = true;
HttpClient client = new HttpClient(handler);
client.BaseAddress = new Uri("http://localhost:9095/");
HttpResponseMessage response = client.PostAsJsonAsync<Customer>("api/values", cust).Result;

Resources