Trying to pass parameters to HTML page in C# webView2 - javascript

I am attempting to navigate to an HTML file using parameters for location (lat and long)
This is a WPF application that has a built in browser which shows data from the google maps api.
I want to instantiate my map given the location parameters in C#
I read this thread:
How to pass information from a WPF app to an HTML page
but I still get file not found. The url works fine without the parameters
String sURL = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\html\\mapview.html";
Uri uri = new Uri(sURL+"?lat="+lat+"&lng="+lng+"");
webBrowser1.Source = uri;
Any ideas as to why im getting these errors?
Not allowed to load local resource
and
ERR_FILE_NOT_FOUND

As mm8 pointed out, because I'm not using a web server it is not possible to pass parameters to my local file.
Reading various threads I had found a solution of installing a local webserver to the project, but since I didn't want to have to configure the web server and add unnecessary load to my projects, I worked around the issue by dynamically changing the coordinates in the HTML file before loading it in
private void LoadMap()
{
// Before loading map, change the trojan horse coordinates to the latest ones by editing the html file
string[] lines = File.ReadAllLines(sURL);
for (int i = 0; i < lines.Length; i++)
{
if (lines[i].Contains("var lat"))
{
lines[i] = "<script>var lat = " + lat + "; var lng = " + lng + ";</script>";
break;
}
}
File.WriteAllLines(sURL, lines);
// We can now load in the desired coordinates
Uri uri = new Uri(sURL);
webBrowser1.Source = uri;
}
Note that this will require a new page load each time, but it is a good solution for changing things that need to be done on page load.
Another thing I tested was calling the script asynchronously. This also worked pretty well
// we need to wait for map initialization (page load) before running our calcRoute script
private async void NavMapLoading() //starts loading content asynchronously
{
await webBrowser1.EnsureCoreWebView2Async(null);
webBrowser1.CoreWebView2.DOMContentLoaded += OnWebViewDOMContentLoaded;
Uri uri = new Uri(AppDomain.CurrentDomain.BaseDirectory + "html\\map_route.html");
webBrowser1.Source = uri;
}
private async void OnWebViewDOMContentLoaded(object sender, CoreWebView2DOMContentLoadedEventArgs arg)
{
webBrowser1.CoreWebView2.DOMContentLoaded -= OnWebViewDOMContentLoaded;
webBrowser1.Focus();
// now we can load destination
await webBrowser1.ExecuteScriptAsync("calcRoute("+origin+","+dest+");");
}

Related

How do I apply basic authentication to a Google Maps API getTileUrl request in Javascript?

Really hope somebody can help here as I've been trying loads of stuff to get this working...
When I call my external tileserver, it requires basic authentication, but there appears to be no way to add this.
We are using the latest production version of Google Maps API.
I call up the tile as follows:
chartMapLayer = new google.maps.ImageMapType({
getTileUrl: function (coord, zoom) {
var tileCoords = xyzToBounds(coord.x, coord.y, zoom).join(",");
return (ChartURL + '/?' +
'SERVICE=WMS' +
'&<params go here.....>' +
'&BBOX=' + tileCoords);
},
maxZoom: 17,
minZoom: 0,
name: "CHARTWORLD",
isPng: true,
tileSize: new google.maps.Size(256, 256)
});
If I use the same code to call a server set up with no basic authentication, it works fine. When I call the server we need to, I receive 401 (Unauthorized) errors.
I have tried setting up an XMLHttpRequest override to append the header to all outgoing requests. Worked for everything EXCEPT the map tile request....
I also tried setting up a proxy page...this approach did actually work, but the requests were being served synchronously, so each tile load was taking about quarter of a second. And there were 16 of them, so it was a really poor user experience.
If anybody knows a way to add authentication to Google Maps API tile requests I'd really appreciate it.
EDIT:
My question above was closed due to needing more debugging data or specific requirements, etc. I am honestly not sure what extra information I need to put.
The WMS server I am using requires basic auth to be provided in the header and, as per the comments, does not accept query parameters.
I have created a proxy and this does work, but takes about 5-6 seconds to draw a full page of tiles on the map, compared to almost instantaneous when done without a proxy using a test server from the same provider without the authentication requirements.
I have tried this with an ashx and an aspx page. My current code uses the aspx page. It is called from the javascript within the getTileUrl function as below:
return ('Charts.aspx?p=' + ChartURL + '/?' +
'SERVICE=WMS' +
'¬VERSION=1.3.0' +
'¬REQUEST=GetMap' +
'¬FORMAT=image%2Fpng' +
'¬CSVALUE=10,5,20,10,1,2,1,500000,100000,200000,1' +
'¬CSBOOL=183' +
'¬TRANSPARENT=false' +
'¬LAYERS=ENC' +
'¬CRS=EPSG%3A3857' +
'¬STYLES=' +
'¬WIDTH=256' +
'¬HEIGHT=256' +
'¬OBJECTFILTERNEGATION=TRUE' +
'¬BBOX=' + tileCoords);
The code behind of the page this calls is as follows:
using System;
using System.IO;
using System.Net.Http;
using System.Web;
public partial class Pages_User_Charts : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string Parameters = Request.QueryString["p"];
string ChartAuth = "";
if (HttpContext.Current.Session["chartAuth"] != null)
ChartAuth = HttpContext.Current.Session["chartAuth"].ToString();
if (ChartAuth.Length > 0 && Parameters.Length > 0)
{
string url = String.Format(Parameters.Replace("¬", "&"));
System.Net.WebClient wc = new System.Net.WebClient();
wc.Headers.Add("ContentType", "application/json");
wc.Headers.Add("Authorization", "Basic " + ChartAuth);
byte[] data = wc.DownloadData(url);
Response.ContentType = "image/png";
Response.OutputStream.Write(data, 0, data.Length);
Response.OutputStream.Flush();
Response.End();
}
}
}
For the sake of moderators and/or others who have marked down and/or closed off this question, I have spent three days investigating, testing, and searching the internet for solutions and ideas to resolve this problem before opening this question here. If more details are needed please comment to let me know or email me...I am asking a genuine question and need help. I am not lazy and expecting others to magically fix my problem, I just need some suggestions.

Why does my request-promise function work in Chrome but not Firefox or Safari?

I'm trying to use a script for a webpage that scrapes and then parses an RSS feed using request-promise. From what I understand, request-promise has to run server-side, so I'm calling the script externally in my html. I've been using localStorage.setItem and localStorage.getItem to pass the variables between the external script and another embedded script that assigns the variables to html elements that should be displayed throughout the page as text.
In Chrome, when the page first loads, it's blank, but then works fine after I refresh it once. In Firefox and Safari, it remains blank no matter how many times I refresh. The issue seems to be that the html is not "receiving" the variables from localStorage.getItem. I suspect it has something to do with the way the different browsers are handling the request-promise function, but I'm stumped. What am I doing wrong?
Here's the request-promise script:
var xmltext
var latlonquery, latquery, lonquery, url
const rp = require('request-promise')
const options = {
headers: {'user-agent': 'node.js'}
}
function doQuery() {
latlonquery = new URLSearchParams(window.location.search)
latquery = latlonquery.get("lat")
lonquery = latlonquery.get("lon")
url = "https://forecast.weather.gov/MapClick.php?lat=" + latquery + "&lon=" + lonquery + "&FcstType=digitalDWML"
}
function doRequest() {
return rp(url,options).then(function(html){
return html
})
}
doQuery()
doRequest().then(function(html){
xmltext = html
localStorage.setItem("xml_says_this", xmltext)
localStorage.setItem("lat_says_this", latquery)
localStorage.setItem("lon_says_this", lonquery)
})
You can see an example of the problem in action here.

How do you accept a value from a user (textbox) and create a Site (when user hits Submit button) using Google Apps Script and UI Services?

I have the following code as a Google Apps Script (deployed as a web app) and have inserted it into my Google Enterprise page as a Google Apps Script Gadget. The UI (panel) loads properly with the label, textBox and button, but when I enter in text and click the button, I get the following error:
Error encountered: The resource you requested could not be located.
Here is my script:
function doGet(e) {
// create all UI elements
var myApp = UiApp.createApplication();
var panel = myApp.createVerticalPanel();
var label = myApp.createLabel('Please enter the name of your new site:');
var textBox = myApp.createTextBox().setName('txtSiteName');
var button = myApp.createButton('Create Site');
var btnHandler = myApp.createServerHandler('createNewSite');
button.addClickHandler(btnHandler);
btnHandler.addCallbackElement(panel);
// add all UI elements to the panel
panel.add(label);
panel.add(textBox);
panel.add(button);
// add the panel to the app
myApp.add(panel);
// return the app to the browser to be displayed
return myApp;
}
// button server handler
function createNewSite(e) {
var domain = SitesApp.getActiveSite().getUrl();
var siteName = e.parameter.txtSiteName;
var newSite = SitesApp.createSite(domain, siteName, 'script_center_demo', "this is just a test page");
return app.close();
}
Also, what is the difference between createSite() and createWebPage()?
EDIT: Ok, so using the same doGet() function above, my createNewSite() function could look like this?
function createNewSite(e) {
var domain = 'my-domain.com';
var siteName = e.parameter.txtSiteName;
var newPage = SitesApp.createSite(domain, siteName, 'script_center_demo', "this is just a test page");
var pageName = 'script_center_demo';
var html = '<div><p>This project aims to....</p></div>';
var site = SitesApp.getSite(domain, site);
site.createWebPage('Script Center Demo', pageName, html);
return app.close();
}
Look at this line:
var domain = SitesApp.getActiveSite().getUrl();
You're need to obtain a domain, e.g. example.com, but this line will yield a URI containing google's domain, and a resource path (that contains your domain). Example:
https://sites.google.com/a/example.com/mySite/
^^^^^^^^^^^
When you attempt to create a new site, it cannot be found as a domain. You need to strip the result of getUrl() down to just the domain name.
If you're the Domain administrator, you can use this instead:
var domain = UserManager.getDomain();
Ordinary domain users don't have access to the UserManager Service, so they would need to parse the site URL to extract their domain. I suggest using parseUri by Steven Levithan to handle the task:
var uri = parseUri(SitesApp.getActiveSite().getUrl());
var domain = parseUri(uri.path.slice(3)).host;
The .slice(3) operation is intended to remove /a/ from the path property of the parsed Site URI. This works on my accounts in multiple domains today - ymmv.
After that, we treat the remaining path as a URI and invoke parseUri() again, extracting the host property, which should be our domain.
Also, what is the difference between createSite() and createWebPage()?
You create an instance of a Site, using the Sites service method SiteApp.createSite. Not much to look at, a Site object is a container, a skeleton - you use the Site.createWebPage() method to create Web Pages that will be contained in the Site, and visible to users, mainly via web browsers.
Edit - Debugging Results
Debugging WebApps is tricky. Get familiar with "View - Execution Transcript", since it will show a trace of execution for your createNewSite() handler function when it's invoked. Using that technique, here's what I found, part 1:
We can't call SitesApp.getActiveSite().getUrl() in the handler, because when it's invoked there is no active site. You're already using the simple work-around of hard-coding the domain.
When trying to get a handle on the new site, you have var site = SitesApp.getSite(domain, site);. This is where your latest "resource error" message was coming from. The site parameter is left-over from insertion of the function - it needs to be a string, matching the site name used in createSite().
You're returning app.close(), but have no app defined in the function.
With those problems fixed, here's problems, part 2:
The dialog lets users enter a site name, but there are restrictions on those that need to be followed to make createSite succeed. The simplest rule is that the site name must be lower case. Why not let users enter the site title, and derive the name from that?
What if the site already exists? That's not handled. Same thing for the page creation, later on.
There's no feedback to the user. The example below has very rudimentary status updates in it, which are appended to the UI.
updated code
function createNewSite(e) {
var app = UiApp.getActiveApplication();
var domain = 'mitel.com';
var siteTitle = e.parameter.txtSiteName;
var siteName = siteTitle.toLowerCase();
var result = 'Results: ';
var site = SitesApp.getSite(domain, siteName); // Check if site already exists
if (site)
result += 'Site "' + siteName + '" exists, ';
else {
// Doesn't exist, so create it
site = SitesApp.createSite(domain, siteName, siteTitle, "this is just a test page");
result += 'Site "' + siteName + '" created with title "' + siteTitle + '", ';
}
var pageName = 'script_center_demo';
var html = '<div><p>This project aims to....</p></div>';
var page = site.getChildByName(pageName); // Check if page already exists
if (page)
result += 'Page "' + pageName + '" exists, ';
else {
// Doesn't exist, so create it
page = site.createWebPage('Script Center Demo', pageName, html);
result += 'Page "' + pageName + '" created, ';
}
result += 'Done.';
// Add result text to UI
var uiResult = app.createLabel(result, true);
app.add(uiResult);
return app.close();
}

how to add dynamic kml to google earth?

We are trying to add dynamic kml to google earth.But we are failing in one situation.
CODE:
var currentKmlObject = null;
function loadkmlGE(){
if (currentKmlObject != null) {
ge.getFeatures().removeChild(currentKmlObject);
currentKmlObject = null;
}
var url = 'test.kml';
google.earth.fetchKml(ge, url, finished);
}
function finished(kmlObject) {
if (kmlObject) {
currentKmlObject = kmlObject;
ge.getFeatures().appendChild(currentKmlObject);
} else {
setTimeout(function() {
alert('Bad or null KML.');
}, 0);
}
}
When we click on button we are calling loadkmlGE() function.We are able to get the kml first time on google earth.If we click second time then we are not getting kml on google earth.But test.kml file is updating new values.So, how we can remove the kml from google earth?
Help would be appreciated.
fetchKml I beleive uses the browser to fetch the file. It will generally cache the file unless told otherwise.
You could arrange for the server to tell the browser it cant cache the file - using HTTP headers. depends on your server how to set that up.
... or just arrange the url to change each time.
var url = 'test.kml?rnd='+Math.random();
or similar. The server will likly ignore the bogus param. But as the URL has changed the browser wont have a cached version.

Different external .js files with same variable names

I'm making a websites that displays noise measurement data from different locations. The data for each location is captured on a sound level meter device and it is then read with a windows-based application. The application then uploads data on a web server as a .js file with an array variable in it. This .js files are refreshed every 5 minutes.
I first created a javascript application that displays live data for a single measuring unit. But now I need to display data on a map for all the locations. The problem is that the windows application on each location makes a file with the same name and same variables only on another location. I'm having some trouble with reading the correct data.
This is what I did so far:
function removejscssfile(filename, filetype){
var targetelement=(filetype=="js")? "script" : (filetype=="css")? "link" : "none" //determine element type to create nodelist from
var targetattr=(filetype=="js")? "src" : (filetype=="css")? "href" : "none" //determine corresponding attribute to test for
var allsuspects=document.getElementsByTagName(targetelement)
for (var i=allsuspects.length; i>=0; i--){ //search backwards within nodelist for matching elements to remove
if (allsuspects[i] && allsuspects[i].getAttribute(targetattr)!=null && allsuspects[i].getAttribute(targetattr).indexOf(filename)!=-1)
allsuspects[i].parentNode.removeChild(allsuspects[i]) //remove element by calling parentNode.removeChild()
}
}
function updateData(){
var numberOfNoiseSniffers = noiseSniffers.length-1;
var j = 0;
for (i=0;i<=numberOfNoiseSniffers;i++) {
file = '../'+ noiseSniffers[i] + "/" + "CurrentMeasurement.js";
$.include(file,function(){
laeq[j] = currentMeas[1][1];
lastUpdate[j] = currentMeas[0][1];
if (j==numberOfNoiseSniffers){
updateMarkers();
}
removejscssfile(file[0], "js");
j++;
});
}
t=setTimeout(function() { updateData() }, 300000);
}
$(function (){
map = new google.maps.Map(document.getElementById("gMap"), myOptions);
//noiseSniffers is an array where I have save all the folder names of different measurement locations
var numberOfNoiseSniffers = noiseSniffers.length-1;
var j = 0;
for (i=0;i<=numberOfNoiseSniffers;i++) {
var file = '../'+ noiseSniffers[i] + "/" + "CurrentMeasurement.js";
//I am using include plugin for jquery to include files because it has a callback for when a file is actually loaded
$.include(file,function(){
//a set of global arrays that keep the data from the loaded file and this data is then displayed in google maps markers
laeq[j] = currentMeas[1][1];
lastUpdate[j] = currentMeas[0][2];
latitude[j] = systemstats[12][5];
longitude[j] = systemstats[11][6];
//checking to see if I am in the process of including the last file
if (j==numberOfNoiseSniffers){
//a function that creates google maps markers
createMarkers();
}
//after that I remove the files that were just included and read
removejscssfile(file, "js");
j++;
});
}
setTimeout(function() { updateData() }, 300000);
});
I got the function for removing my .js file here: Dynamically removing an external JavaScript or CSS file.
And this is the jquery plugin for loading the .js file: Include File On Demand.
The initial load usually works (sometimes it happens that only one or no markers get loaded. But the update function mostly returns the same data for both locations.
So what I want to know is, how can I firstly make my code working and how to optimize it. I posted just the main parts of the javascript code, but I can provide all the code if it is needed. Thanks for any help.
I think you need some sort of JSONP-like solution.
Basically load data on the server side, then wrap it in a method call before returning it to client side. Your response should look something like this:
var location_data = [1,2,3,4]
updateLocation('location_id', location_data)
Now you define an updateLocation() function in your client side script. Now, every time you need new data, you create new 'script' tag with src pointing to your server side. When the response is loaded, your updateLocation() will be invoked with correct params.
I hope this is clear enough
You can maybe try some form of namespacing
i exactly dont understood your problem, but you may try this
//put your code inside an anonymous function and execute it immediately
(function(){
//your javascript codes
//create variable with same names here
//
})();

Categories