"Disconnected" response from HttpClient.PostAync() - c#

I'm trying to fix an issue with a legacy asp.net WebForms application written about 6 years ago. I'll try to explain and hope that someone can see a fix.
Our application supports what we call an "API". Really it's just a couple of pages intended to be displayed within the pages of our customers' websites. We also provice a sample application that shows how to use it.
The sample app has some form fields for the caller to provide values. When submitted, we create a string of HTML containing a elelement with the tag that
submit()'s the form on postgback.
Example:
...
form1.submit();
This method works successfully as long as the end user puts our domain in thier trusted sites. Otherwise the user gets permission denied errors. However, recently, we've had a couple customers refuse to add us to trusted sites and
want the issue fixed another way.
One approach I've tries is to use HttpClient.PostAsync() to do what the form/script above does but from the server side.
public HttpResponseMessage Post(string address, MediaTypeWithQualityHeaderValue acceptType, List<KeyValuePair<string, string>> data)
{
using (HttpClient client = new HttpClient())
{
//client.BaseAddress = new Uri(address);
client.DefaultRequestHeaders.Accept.Add(acceptType);
HttpContent content = new FormUrlEncodedContent(data);
HttpResponseMessage response = client.PostAsync(address, content).Result;
return response.EnsureSuccessStatusCode();
}
}
It's called like this:
string hash = GenerateHashValue();
List<KeyValuePair<string, string>> data = this.BuildPostData(hash);
MediaTypeWithQualityHeaderValue acceptType = new MediaTypeWithQualityHeaderValue("text/html");
HttpResponseMessage msg = Post(this.GetPostTargetUrl(), acceptType, data);
var task = msg.Content.ReadAsStringAsync();
task.Wait();
string result = task.Result;
Response.Write(result);
Response.End();
The response HTML is successfully written into the but it's essentally "disconnected" - nothing works after that. Normally, using the / method about uses can navigate in the iframe to other pages on our
site.Looking at it in fiddler, I see that some of the posts and redirects that I see when using the current / method is happeing and I get 404s for many of the javascript files coming from our site.
Can anyone suggest another approach in which I would not have XSS errors but a "connected" iframe?
Thanks,
Dan

Related

API GET Request Returns HTML/Text instead of JSON

This is my first time working with a RESTful API and Xamarin and etc. I have so far made a simple REST API. I have written a GET call to it that, if I write http://localhost:[num]/api/Name, it will return a JSON file of the matching Emu's information. I have tested this with Postman, so I know that it works.
I have now written an app that will call this API in order to catch this information and then display it. So far, I've got it connected to the server hosting my API, but I'm unable to get it to return JSON. Instead it seems to be returning text/HTTP.
From what I've searched up on previous Stack Overflow threads, it seems that I was missing Headers requesting that reply be in a JSON format. When I added in code that was on the official .NET documentation on Microsoft's website, it gave me issues with my Json Deserialiser. I have also added in the information in the header to make sure that it returns json.
Here is the code for the function:
async private void Submit_OnClicked(object sender, EventArgs e)
{
var nameValue = EmuName.Text;
var baseAddr = new Uri("http://my_url/HelloEmu/");
var client = new HttpClient { BaseAddress = baseAddr };
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
string url = (string)nameValue;
var returnedJson = await client.GetStringAsync(url);
Models.EmuItemModel MyEmu = JsonConvert.DeserializeObject<Models.EmuItemModel>(returnedJson);
ReturnedName.Text = MyEmu.Name;
ReturnedAge.Text = MyEmu.Age.ToString();
ReturnedWeight.Text = MyEmu.Weight.ToString();
My code actually faults on the line ReturnedWeight.Text = MyEmu.Weight.ToString()
But I'm guessing the more majour issue is occuring during deserialisng the object, because it seemingly "skips" over the preceeding two lines when I run it in the debugger.
When I run it in Visual Studio 2019, the value of "returnedJson" is this:
"<html><head><meta http-equiv=\"refresh\" content=\"0;url=http://lookup.t-mobile.com/search/?q=http://my_url/HelloEmu/Keith&t=0\"/></head><body><script>window.location=\"http://lookup.t-mobile.com/search/?q=\"+escape(window.location)+\"&r=\"+escape(document.referrer)+\"&t=0\";</script></body></html>"
I think this is an HTML output. I would love any hints about what on earth I'm doing wrong!
EDIT: Since it almost seems like the HTML is returning an error message, perhaps it could do with my url??? I've published the website using the File system method. So to access the API in Postman I'll use http://localhost:[port]/api/values, calling my website in a regular ol' browser makes it go http://my_url/HelloEmu. I get a 403 "no directory" method in return...
EDIT: Here is the Postman code:
enter image description here
Usually it happens because there are missing headers or some other malformed request, Download RestSharp DLL from NuGet, and then you can use the following, in postman, go to "Code":
And choose C# you will see a code snippet (Example):

Scraping multiple lists from a website.

I'm currently working on a web scraper for a website that displays a table of data. The problem I'm running into is that the website doesn't sort my searches by state on the first search. I have to do it though the drop down menu on the second page when it loads. The way I load the first page is with what I believe to be a WebClient POST request. I get the proper html response and can parse though it, but I want to load the more filtered search, but the html I get back is incorrect when I compare it to the html I see in the chrome developers tab.
Here's my code
// The website I'm looking at.
public string url = "https://www.missingmoney.com/Main/Search.cfm";
// The POST requests for the working search, but doesn't filter by states
public string myPara1 = "hJava=Y&SearchFirstName=Jacob&SearchLastName=Smith&HomeState=MN&frontpage=1&GO.x=19&GO.y=18&GO=Go";
// The POST request that also filters by state, but doesn't return the correct html that I would need to parse
public string myPara2 = "hJava=Y&SearchLocation=1&SearchFirstName=Jacob&SearchMiddleName=&SearchLastName=Smith&SearchCity=&SearchStateID=MN&GO.x=17&GO.y=14&GO=Go";
// I save the two html responses in these
public string htmlResult1;
public string htmlResult2;
public void LoadHtml(string firstName, string lastName)
{
using (WebClient client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
htmlResult1 = client.UploadString(url, myPara1);
htmlResult2 = client.UploadString(url, myPara2);
}
}
Just trying to figure out why the first time I pass in my parameters it works and when I do it in the second one it doesn't.
Thank you for the time you spent looking at this!!!
I simply forgot to add the cookie to the new search. Using google chrome or fiddler you can see the web traffic. All I needed to do was add
client.Headers.Add(HttpRequestHeader.Cookie, "cookie");
to my code right before it uploaded it. Doing so gave me the right html response and I can now parse though my data.
#derloopkat pointed it out, credits to that individual!!!

How to specify message body in a WebClient?

In the console, I follow up a call the site I'm on is is making and I can see the address (some.site.com/gettoken), message header and something that FF calls Message Body. It's in the latter that I can see the credentials that I've entered on the site that are being sent.
So, I've got the URL and the message body. Then, I've tried to implement the behavior using C# for my Azure service layer like so.
String url = #"https://some.site.com/gettoken";
String credentials = "username=super&password=secret";
using (WebClient client = new WebClient())
{
String output = client.UploadString(url, credentials);
result = output;
}
However, I get error 400 - bad result. What did I miss?
I've googled for some stuff but the only remotely relevant hits are talking about the upload methods, which I've used. Am I barking up the wrong tree entirely or just missing something tiny? Some people seem to get it to work but they're not tokenizing around. And I'm not certain enough to determine whether it's of relevance or not.
So, as a summary of what has been discussed in the comments: you can use the more modern HttpClient instead.
Note that this is the System.Net.Http.HttpClient and not Windows.Web.Http.HttpClient.
An example implementation could look like this:
public async Task<string> SendCredentials()
{
string url = #"https://some.site.com/gettoken";
string credentials = "username=super&password=secret";
using(var client = new HttpClient())
{
var response = await client.PostAsync(url, new StringContent(credentials));
return await response.Content.ReadAsStringAsync();
}
}
You might also be interested in System.Net.Http.FormUrlEncodedContent which allows you to pass in the parameters and their values so you don't have to construct the credentials value yourself.
More information on async/await.

how to conceptually make a post request to web api from c# program as if the it's coming from html form

I have been banging my head against the wall for the past 1 week now but without any success. Actually I'm writing a C# code(a web api controller action) to call another web api to make a post request with some json data payload in the request body. Syntax-wise there is nothing wrong with the code. But when I directly call the service(web api service) from web browser I get an Html form that has a multiline text box in it, rollback property (as radio button for true and false value for this property), drop down box with 2 options such as html and json (to get response in either format) and a button(for sending request to the server and making edits in the database). Now when I manually put json data inside text box and click the button on that html form edits are done successfully in the database but when programmatically(from my C# code) I send the same json data payload and make a post request edits are never done successfully rather I get an html response body through Fiddler that says status code success 200 but unable to complete operation,some parameters couldn't be recognized.
Here is my code
private static async Task<HttpResponseMessage> GeometryUpdateAsync(Feature updatedFeature, FeatureType featureType, int? objectid = null)
{
var jsonObject = new JObject();
dynamic esriId = jsonObject;
if (objectid == null)
{
objectid = updatedFeature.OBJECTID;
}
esriId.OBJECTID = objectid;
var mergedJsonString = JsonConvert.SerializeObject(new
{
geometry = JObject.Parse(updatedFeature.Geometry.ToString()),
attributes = JObject.Parse(esriId.ToString())
});
mergedJsonString = String.Format("[{0}]", mergedJsonString);
HttpResponseMessage response = null;
using (var client = new HttpClient())
{
//string arguments = "rollbackOnFailure=true&f=pjson&features=";
client.BaseAddress = new Uri("somebaseaddress");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.Timeout = TimeSpan.FromSeconds(500.00);
//response = await client.PostAsJsonAsync("someuri", arguments + mergedJsonString);
response = await client.PostAsync("someuri", mergedJsonString, new System.Net.Http.Formatting.JsonMediaTypeFormatter());
if (response.IsSuccessStatusCode)
{
var v = response.Content.ReadAsStringAsync().Result;
}
}
}
When I look at the request body (through fiddler while making a post request through Html form) request body looks like
features=%5B%7B%22geometry%22%3A%7B%22paths%22%3A%5B%5B%5B-91.3888577181506%2C39.703158271352621%5D%91.381838690201192%2C39.690323806398723%5D%2C%5B-91.383241723424632%2C39.689645139311914%5D%2C%5B-91.3849700567206%2C39.6888078408094%5D%2C%5B-91.3861256828518%2C39.688248198995353%5D%5D%5D%7D%2C%22attributes%22%3A%7B%22OBJECTID%22%3A21%7D%5D&gdbVersion=&rollbackOnFailure=true&f=pjson
and the request body for the post request made programmatically looks likes
"[{\"geometry\":{\"paths\":[[[-91.3888577181506,39.703158271352621],[-91.381838690201192,39.690323806398723],[-91.383241723424632,39.689645139311914],[-91.3849700567206,39.6888078408094],[-91.3861256828518,39.688248198995353]]]},\"attributes\":{\"OBJECTID\":21}}]"
Even I tried appending this
string arguments = "rollbackOnFailure=true&f=pjson&features=";
in my commented out code above (where I'm using PostAsJsonAsync) to make the request body look like as if it's coming from Html form. But no success, even I'm not sure whether the JSonFormatter takes this arguments string in to account or just leaves it while serializing/deserializing during the run time. And the post request body that I get after appending "arguments" string to Json string looks like this
"rollbackOnFailure=true&f=pjson&features=[{\"geometry\":{\"paths\":[[[-91.3877577181506,39.703158271352621],[-91.36047320856953,39.702616420911333],[-91.383241723424632,39.689645139311914],[-91.3849700567206,39.6888078408094],[-91.3861256828518,39.688248198995353]]]},\"attributes\":{\"OBJECTID\":21}}]"
But still no success, Now I'm totally running out of ideas as to how to call web api service from my C# code so that web api thinks it's coming from that Html form and end up successfully doing edits in the database programmatically. All suggestions and ideas will be highly appreciated.
The trick lies somewhere else, I was using HttpClient to simulate browser post request and get result in c#. But in this particular scenario HttpClient is of no use. I changed to HttpWebRequest after seeing a code at How to make a post call to a Web Api Action? from utlimate_programmer_BR and it did the trick, again HttpClient was a bad choice by me to get this particular thing done.

C# Navigating through sites using HttpClient WP

Been looking for a solution, but I havent been able to get a result that answers my questions.
I'm looking for a way to go through sites (basically read the html), using the HttpClient. I'm making an app for windows phone, so some options may be disabled.
I want to make a program that goes to a site, logs in, and then is able to retrieve the access html source code.
So when I log in, a session id is saved in a CookieContainer, so I'll be able to access the sites that require login. How would I do this using the HttpClient :)?
HttpClient manages authentication cookies automatically for you. Just make sure you re-use the same HttpClient instance for multiple requests. Under the covers, HttpClient creates an instance of HttpClientHandler which has a CookieContainer.
Here is an example that logs into the NerdDinner site and retrieves a secured page.
var httpClient = new HttpClient();
// Create login payload
var body = new Dictionary<string, string>()
{
{"UserName", "bob"},
{"Password", "xyz"},
{"RememberMe", "false"}
};
var content = new FormUrlEncodedContent(body);
// POST to login form
var response = await httpClient.PostAsync("http://www.nerddinner.com/Account/LogOn?returnUrl=%2F", content);
// Make new request to secured resource
var myresponse = await httpClient.GetAsync("http://www.nerddinner.com/Dinners/My");
var stringContent = await myresponse.Content.ReadAsStringAsync();

Categories

Resources