I'm trying to load a webview using HttpRequestMessage in Windows Phone 8.1. The problem is that the Content-Type header is missing in the content headers when checked in Fiddler.
byte[] postData = GetWebviewPostDataBytes();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, prepareUri(url));
var httpContent = new HttpBufferContent(postData.AsBuffer());
httpContent.Headers.Add("Content-Type", GetContentType());
request.Headers.Add("User-Agent", GetUserAgent());
request.Content = httpContent;
webView.NavigateWithHttpRequestMessage(request);
I found some links where this is posed as an internal bug. Can someone tell me a workaround to this?
The only solution I've found for this is to use a form to load your page.
I'm loading a local HTML page which I'm generating with my POST parameters. This page contains an hidden HTML form which I will submit once the page will be loaded.
The web page loading is then:
generate a local HTML page with a form and your parameters in hidden input fields
load this page in your webview
once the page is loaded, request a submit of the form using the webpage postContent() function
the webview will then navigate to the expected webpage with the content-type header set
This sample code is in WinJS but it can easily be transposed in C# since it is the same webview component.
var htmlContent = "<html><head><script type='text/javascript'>function postContent(){document.getElementById('postForm').submit();}</script></head><body><form id='postForm' action='{targetUrl}' method='post'>{inputFields}</form></body></html>";
var inputFields = "";
var iterator = payloadContent.first();
while(iterator.hasCurrent)
{
inputFields += "<input hidden='on' name='{n}' value='{v}'/>".replace("{n}", iterator.current.key).replace("{v}", iterator.current.value);
iterator.moveNext();
}
var htmlContent = htmlContent.replace("{targetUrl}", "YOUR URL HERE").replace("{inputFields}", inputFields);
this._webviewElement.navigateToString(htmlContent);
In the page loaded event you will then have to request the webview to execute the 'postContent()' javascript function to submit the form.
this._webviewElement.invokeScriptAsync("postContent");
Hope this helps.
Related
I wrote a program that includes an embedded web browser that loads a website which have a changing part (the part changes about 2 times a week and it have no regular timing pattern) that I want to search for a particular part in the opened webpage source code after refreshing the webpage in a specified time interval.
I found many things similar to my question but this is what I want and those questions doesn't have:
search embedded webpage source (they searching the webpage without embedding, and I had to embed it because I had to login before I see the particular page)
so this is the procedure I'm trying to do:
1- open a website in embedded web browser
2- after user logged in, with a press of button in program, it hides the embedded
web browser and start to refresh the page in a time interval (like
every minute) and search if the particular code changed in the source of
that opened webpage
any other/better Ideas appreciated
thanks
Many years ago I wrote an app to reintegrate forum posts from several pages into one and I struggled with the login issue too and thought it was only possible using an embedded browser. As it turns out, it's possible to use System.Net in .NET to handle web pages that need a login as you can pull the cookies out and keep them on hand. I would suggest you do that and move away from the embedded browser.
Unfortunately I wrote the code in C# originally, but as it's .NET and is mostly classes-based, it shouldn't be too difficult to port over.
The Basic Principle
Find out what information is included in the POST when you login, which you can do in Chrome with developer mode on (F12). Convert that to a byteArray, POST it to the page, store the cookies and make another call with the cookie data later on. You will need a class variable to hold the cookies.
Code:
private void Login()
{
byte[] byteArray = Encoding.UTF8.GetBytes("username=" + username + "&password=" + password + "&autologin=on&login=Log+in"); // Found by investigation
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("yourURL");
request.AllowAutoRedirect = false;
request.CookieContainer = new CookieContainer();
request.Method = "POST";
request.ContentLength = byteArray.Length;
request.ContentType = "application/x-www-form-urlencoded";
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
WebResponse response = request.GetResponse();
if (((HttpWebResponse)response).StatusCode == HttpStatusCode.Found)
{
// Well done, your login has been accepted
loginDone = true;
cookies = request.CookieContainer;
}
else
{
// If at first you don't succeed...
}
response.Close();
}
private string GetResponseHTML(string url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.AllowAutoRedirect = false;
// Add cookies from Login()
request.CookieContainer = cookies;
request.ContentType = "application/x-www-form-urlencoded";
WebResponse response = request.GetResponse();
string sResponse = "";
StreamReader reader = null;
if (((HttpWebResponse)response).StatusCode == HttpStatusCode.OK)
{
reader = new StreamReader(response.GetResponseStream());
sResponse = reader.ReadToEnd();
reader.Close();
}
response.Close();
return sResponse;
}
Hope that helps.
I had to change to C# and I found what I was looking for:
string webPageSource = webBrowser1.DocumentText;
That gave me the source of web page opened in webBrowser1 control.
I'm trying to download a dynamically generated file from the server using a hidden form.
Below is the angular function that I'm using to submit the hidden form
$scope.downloadCsv = function() {
var dataset = JSON.stringify($scope.dataset);
var body = $('body');
var reportParamJson = angular.toJson($scope.dataset);
var hiddenForm = "<form action='/Reports/SaveTestCsv' method='POST' target='_blank'><input type='hidden' name='dataset' value='" + dataset + "'/ ><button id='submitCSV' type='submit'></button></form>";
body.append(hiddenForm);
$('#submitCSV').click();
}
Below is the .net mvc method to generate the response with the file
[HttpPost]
public ActionResult SaveTestCsv(string dataset)
{
var data = JsonConvert.DeserializeObject<MyObject>(dataset);
var binary = getTestCSV(data);
var file = File(binary, "text/csv", "test.csv");
return file;
}
Below is the relevant html code from the partial html page that I'm including in the view using ng-include
<div>Download CSV</div>
<div ng-grid="gridOptions"></div>
.
When I click on "Download CSV", Chrome, FF and IE10 prompts me to save the file without refreshing the page/view, but on IE8/9, the page is refreshed, so the content from the ng-include tag is gone, in particular the html I posted above is no longer present.
I'm wondering if this has something to do with the hashbang in the url from IE8/9 and is there any way to fix this?
Edit
I ended up removing routing from angular completely and just use .net MVC to do the routing for me, and then it's working on IE8
I'd like to create an application that receives formatted text (RTF) or html, renders it an show it page by page..
Is there any control that aims to do that?
I tried to use the RichEditBox control to load a file but it stucks during the operation:
var file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(#"myFile.rtf");
using (var memstream = await file.OpenReadAsync())
{
MainText.Document.LoadFromStream(Windows.UI.Text.TextSetOptions.ApplyRtfDocumentDefaults, memstream);
}
I tried to load an HTML file this way:
var file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(#"myFile.htm");
var stream = await file.OpenAsync(FileAccessMode.Read);
string app;
using (StreamReader rStream = new StreamReader(stream.AsStream()))
{
app = rStream.ReadToEnd();
}
myWebView.NavigateToString(app);
But I cannot find a way to "count" the lenght of the parsed text to chunk it in pages..
There is any other way or library to do that? Any example online?
If you want to show your HTML contents in pages then you can use RichTextBlock with RichTextBlockOverflow. RTF is not supported to RichTextBlock.
how to inject RTF file to RichTextBlock in c#/xaml Windows store app
Showing Html in WinRT with RichTextBlock or other component
XAML text display sample
its many days reading hundreds of ways to help me make what I really need. No success at all.
What I need is this:
1) Having a button which only works when the tab has a certain url.
2) After clicking it, must read page's source and then get some pieces of it to send them to my server page in order to check my database for recordcounts (I assume with AJAX & javascript). Then this page should send back to the extension its responses and populate the popup html.
Looks easy I know, but please I need the workflow if not the required codes for the extension.
Thank you so much!
ok so you can chceck selected tab and it's url with:
chrome.tabs.getSelected(null,function(tab) {
workWithUrl(tab.url);
});
...
function workWithUrl(url){
if (url == ...
...
}
To be able to chceck this you need to add permission for "tabs"
To process page source code, send it to web service and change popup.html:
var xhr = new XMLHttpRequest();
xhr.open("POST", "__server adress___", true);
//headers
xhr.setRequestHeader("Content-Type", "application/json");
//response
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
//response from service to popup.html
document.body.innerHTML = xhr.responseText;
}
}
//process page here
xhr.send(pageText);
You have to add permission for server adress to manifest as well and everything should be executed from popup.js (or html).
i want to load the Kepler reference Page with HttpClient like this:
string resourceAddress = _url;
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, resourceAddress);
HttpClient httpClient = new HttpClient();
// Do not buffer the response:
HttpResponseMessage response = new HttpResponseMessage();
response = await httpClient.SendAsync(request,
HttpCompletionOption.ResponseContentRead);
using (Stream responseStream = await response.Content.ReadAsStreamAsync())
{
int read = 0;
byte[] responseBytes = new byte[(Int32)responseStream.Length];
do
{
read = await responseStream.ReadAsync(responseBytes, 0, responseBytes.Length);
} while (read != 0);
}
But i think, the Page won´t be loaded complete, like without all images and iframes etc...
Downloading just the first piece of html is rarely going to be enough to give you all the elements of the page, even if you parse it and include all the linked images etc. There is also css and javascript that will bring new content into view when you open a page in a browser and getting all this yourself is going to be an effort similar to implementing your own browser. Your best bet would be to either just load the page once in a WebView control and let it cache its content or use a WebView and scan the DOM to try to get all the elements. You could also write a web service that would download the page for you and just deliver you the whole package... assuming that the page doesn't require authentication.