Controller received 2 request for every page request - javascript

I have modified the Map Route in my Dot Net Core application that for every request goes to one controller, so not lots of controller or Action Result is needed for each page that we build.
greedy Routing
routes.MapRoute("", "/{*article}",
defaults: new { controller = "Pages", action = "Killme" });
In Page Controller build an object that has list of CSS and JavaScript locations, this object is being passed to Page view
public IActionResult Killme()
{
var PageInfo = GetPage_Data();
ViewBag.PageInfo = t;
return View("Pages");
}
and i have tried to pass this information as model or view bag to Page view.
in the Page view i try to build the JavaScript and CSS dynamically based on the model like
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
#{
RootObject PageInfo = ViewBag.PageInfo;
foreach (var JavaScript in PageInfo.js)
{
var JSsrc = JavaScript.src;
<script type="text/javascript" src="#JSsrc ">
</script>
}
<script type="text/javascript" src=""></script>
</head>
<body>
</body>
</html>
Now the Issue is when i build the JavaScript the controller is called 2 times and the page is being rendered 2 times, when i comment the
<script type="text/javascript" src="#JSsrc ">
</script>
the page controller will get called once,
any help regarding why this happening and what am i doing wrong would be appreciated

The reason for this behavior is that the staticFileHandler is either not configured or is not able to find your Javascript file and passes the request further down the pipeline. The MVC handler captures all requests (because of your route) and returns therefore the same page again.
First check that your startup class uses the staticFileHandler before the mvcHandler, so something like this:
public class Startup
{
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseStaticFiles();
..
app.UseMvc();
}
}
Secondly make sure that your Javascript is placed inside the wwwroot and uses the correct path.So a file like wwwroot/js/mysite.js should a script tag like:
<script src="/js/mysite.js"></script>
These improvements should resolve your issue.

Related

GWT Java - How to close the window (Log Out)

I have read that to Log Out of the application you need to close the window and I found this code:
This answer has what you are looking for:
How to run JavaScript function from GWT Java with JSNI?
Specifically in Java:
myButton.addClickHandler(new ClickHandler(){
public void onClick(ClickEvent event) {
closeWindow();
};
});
public static native void closeWindow() /*-{ $wnd.closeWindow();}-*/;
Then in JavaScript in your app's .html page:
<script type="text/javascript" language="javascript">
function closeWindow() {
window.open('','_self','');
window.close();
}</script>
I have implemented this in my application by:
//Log Out Button
Button logOutButton = new Button("Log Out");
logOutButton.addClickHandler(new ClickHandler(){
public void onClick(ClickEvent event) {
closeWindow();
}
});
public static native void closeWindow() /*-{ $wnd.closeWindow();}-*/;
And the HTML:
<!doctype html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<!-- -->
<!-- Consider inlining CSS to reduce the number of requested files -->
<!-- -->
<!-- <link type="text/css" rel="stylesheet" href="org.AwardTracker.AwardTracker.AwardTracker.css"> -->
<!-- -->
<!-- Any title is fine -->
<!-- -->
<title>Wrapper HTML for AwardTracker</title>
<!-- -->
<!-- This script loads your compiled module. -->
<!-- If you add any GWT meta tags, they must -->
<!-- be added before this line. -->
<!-- -->
<!-- script language="javascript" src="org.AwardTracker.AwardTracker/org.AwardTracker.AwardTracker.nocache.js" --><!-- /script -->
<script src="org.AwardTracker.AwardTracker/org.AwardTracker.AwardTracker.nocache.js">
<type="text/javascript">
function closeWindow() {
window.open('','_self','');
window.close();
}
</script>
</head>
<!-- -->
<!-- The body can have arbitrary html, or -->
<!-- we leave the body empty because we want -->
<!-- to create a completely dynamic ui -->
<!-- -->
<body>
<!-- OPTIONAL: include this if you want history support -->
<iframe id="__gwt_historyFrame" style="width:0;height:0;border:0"></iframe>
</body>
</html>
However, I get the following error on the lines:
closeWindow();
"The method closeWindow() is undefined for the type new ClickHandler(){}"
public static native void closeWindow() /*-{ $wnd.closeWindow();}-*/;
Multiple markers at this line
- Syntax error, insert "EnumBody" to complete BlockStatement
- Syntax error on token "void", # expected
- Syntax error, insert "enum Identifier" to complete
EnumHeaderName
Thank you to all who responded. Based on your responses...
I am using sessions like (via RemoteServiceServlet) in my app. Therefore, as per below in the responses, I need to invalidate session first followed by removal of element from dom. So tried the following:
On the client side:
logOutButton.addClickHandler(new ClickHandler(){
public void onClick(ClickEvent event) {
//Invalidate the session and then reload the application.
AsyncCallback<Void> callback = new InvalidateSessionHandler<Void>(SelectPersonView.this);
rpc.invalidateSession(callback);
}
});
class InvalidateSessionHandler<T> implements AsyncCallback<Void> {
SelectPersonView view;
public InvalidateSessionHandler(SelectPersonView view) {
this.view = view;
}
public void onFailure(Throwable ex) {
System.out.println("RPC call failed - InvalidateSessionHandler - Notify Administrator.");
Window.alert("Connection failed - please retry.");
}
public void onSuccess(Void result) {
//Reload the application.
Window.Location.assign("/");
}
}
On the server side:
public void invalidateSession() {
getThreadLocalRequest().getSession().invalidate(); // kill session
}
This seems to work. However, I am having trouble testing more than one session locally and I do not have a test server I can deploy to. So can I please ask for someone who knows what they are doing in this space to check it to ensure I am not introducing issues into production. My greatest concern is that this will log everyone out. I am particularly toey because I had a situation where sessions were not compartmentalised and users could see other people's data. This has been fixed and I do not want to break that fix!!
You cannot close a window using JavaScript if the window was opened by a user. You can only close a new window that was opened by your app.
Closing window will have no effect on user authentication as most authentication mechanisms rely on server sessions or cookies.
If your authentication is session-based, when a user clicks on the Log Out button you need to (1) invalidate user's session, and (2) reload your app, which will display default entry point for non-authenticated users (home page or login page).
Javascript can only close the page if it is opened by same script. So closeWindow() won't even work. So :
If you are not using sessions in your app i.e. you think that only closing the window is a goal to achieve. Then simply delete that iframe from DOM rather closing page. (You can do that by using js.)
document.getElementById('iframeid').innerHTML = '';
If you are using sessions like (via RemoteServiceServlet) in your app, then you need to invalidate session first followed by removal of element from dom. (For this i am not sure how to do.)
Or
Instead of removal, you can just reload the iframe (which is considered to be as a reload of your app):
document.getElementById('iframeid').src =
document.getElementById('iframeid').src
This is the final code I used:
I am using sessions (via RemoteServiceServlet) in my app. Therefore I need to invalidate the session first followed by removal of element from dom. So the following is the final code:
On the client side:
logOutButton.addClickHandler(new ClickHandler(){
public void onClick(ClickEvent event) {
//Invalidate the session and then reload the application.
AsyncCallback<Void> callback = new InvalidateSessionHandler<Void>(SelectPersonView.this);
rpc.invalidateSession(callback);
}
});
class InvalidateSessionHandler<T> implements AsyncCallback<Void> {
SelectPersonView view;
public InvalidateSessionHandler(SelectPersonView view) {
this.view = view;
}
public void onFailure(Throwable ex) {
System.out.println("RPC call failed - InvalidateSessionHandler - Notify Administrator.");
Window.alert("Connection failed - please retry.");
}
public void onSuccess(Void result) {
//Reload the application.
Window.Location.assign("/");
}
}
On the server side:
public void invalidateSession() {
getThreadLocalRequest().getSession().invalidate(); // kill session
}
getThreadLocalRequest().getSession().invalidate(); returns me to my login window.
Window.Location.assign("/"); returns me to the tomcat page.
So use which ever suits you.

WebView.InvokeScriptAsync not working in universal app

I am using a webview to display a certain html file, However, when I call InvokeScriptAsync, I keep encountering the error.
"Unknown name. (Exception from HRESULT: 0x80020006 (DISP_E_UNKNOWNNAME))". This occurs eventhough the script is called in NavigationComplete or DOMContentLoaded.
I prepared a simple app to debug this problem and I noticed that when the script is in a separate .js file, the error occurs. But if it is placed in the html file, the error would not occur.
I am hoping to have the script in a separate file since I have a quite a lot of functions to implement and I would be using some third party scripts so it would not be maintainable having all the scripts on the html file.
BTW, I did try the same code in a non-universal app and just used Windows 8.1 store app and it would work correctly even with the script stored in a separate file. That is why there must be some setting I am missing to make this work in a universal app.
This is my MainPage code:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
MapWebView.NavigationCompleted +=MapWebView_NavigationCompleted;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
Uri url = new Uri("ms-appx-web:///Common/Web/SamplePage.html");
MapWebView.Navigate(url);
}
private async void MapWebView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
{
try
{
await MapWebView.InvokeScriptAsync("SayHello", new string[] { "Hello! This is a test parameter" });
}
catch(Exception e)
{
string error = e.Message;
}
}
}
NOT WORKING (script is in a separate file which is sample.js):
html file:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<script type="text/javascript" src="sample.js"></script>
<p>Parameter From Script File:</p> <div id="paramDiv"></div>
</body>
</html>
sample.js file:
function SayHello(parameter)
{
document.getElementById('paramDiv').innerHTML = parameter;
}
WORKING (script is in the html file):
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<script>
function SayHello(parameter) {
document.getElementById('paramDiv').innerHTML = parameter;
}
</script>
<p>Parameter From Script File:</p> <div id="paramDiv"></div>
</body>
</html>
Here is the setup of my project:
I have my project setup as a universal app. In the shared code part of the universal app, I have the following files
Common (folder)
Web
SamplePage.html
sample.js
I found the solution to this problem after wasting my whole day on it.
It is caused by incorrect tagging of javascript files in *.Shared.projitem.
The javascript files are tagged as NONE in the ItemGroup which seems to cause it not being found. To make it visible to the project, change it to Content.
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)Common\Web\sample.js" />
</ItemGroup>
Kindly refer to this link where I also posted the solution.
https://social.msdn.microsoft.com/Forums/windowsapps/en-US/b29feddb-ae39-4580-9114-43839aabbcf2/webviewinvokescriptasync-not-working-in-universal-app?forum=winappswithcsharp

Getting data from Spring MVC in Angular JS in the initial view call

I am new to Angular JS, I have created a Spring MVC web application with Angular JS, I know that from view we can call REST services from Angular JS using resource, restangular, http , But say in Spring form the Controller a view is been triggered and for loading the datas through angular within the view again a REST call from angular is been called from view to the server and gets the datas thereafter for loading, Instead is there any way to pass the json object while triggering the view from Spring controller to the Angular JS at the first time itself.
I have done a similar thing, its working fine but don't know whether its a good approach or not.
Spring controller
#RequestMapping("/getemployee")
public ModelAndView helloWord(){
JSONArray employeeJsonArray = // contains all the information of the employee
return new ModelAndView("employee", "employee",employeeJsonArray);
}
employee.jsp
<html ng-app="myApp">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Spring 3.0 MVC Series: Hello World</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js"></script>
<script>
var app = angular.module('myApp', []);
app.controller('MyCtrl', function($scope) {
$scope.employee = [];
$scope.loadData = function(employee)
{
$scope.employee = JSON.parse(employee);
};
});
</script>
</head>
<body ng-controller="MyCtrl">
{{loadData('${employee}')}}
<input type="text" ng-value="employee[0].name"/>
</body>
</html>
Angular really shines when you use it in a "single" page application, so I would suggest using it as you suggested in your "existing approach" as it moves you closer to a single page app design, however, if you are just trying to get some of the features of Angular in an existing request/response application, then you could send your html payload with the data in ng-init as this page demonstrates. It's a RoR example, but I think the point is clear. I think it is a bit of hack, but should get the job done.
<body ng-init="angularVariable = ${variableFromServer}">
html/angular ...
</body>
I recently switched to using angular, the beauty of it is you can ditch jsp's entirely and just have static html as the frontend. Served as a static resource by spring.
To initially populate your form/tables/whatever - lots of different options do it in javascript/angular. But its nice to keep your view seperate from your controllers (ie don't use jsp's).
You can use below code for get user logging,
<input type="text" ng-model ="currentLoging" ng-init= "currentLoging='${pageContext.request.userPrincipal.name}'" />

Problems with SkyScanner Widget in webpage

I am following this example to include a SkyScanner widget on my website:
http://business.skyscanner.net/portal/en-GB/Documentation/Widgets
For some reason I just get an empty div - could this be something to do with the key? When I clicked on the activation link I got from SkyScanner for the widget key, I got a page saying the following:
Description: An application error occurred on the server. The current custom error settings for this application prevent the details of the application error from being viewed remotely (for security reasons). It could, however, be viewed by browsers running on the local server machine.
Details: To enable the details of this specific error message to be
viewable on remote machines, please create a tag within
a "web.config" configuration file located in the root directory of the
current web application. This tag should then have its
"mode" attribute set to "Off".
I have created a web.config file with the following code:
<!-- Web.Config Configuration File -->
<configuration>
<system.web>
<customErrors mode="Off"/>
</system.web>
</configuration>
I've had a look at 'inspect element' on Chrome and get the error
Uncaught TypeError: Object # has no method 'write'
api.ashx?key=[KEY]:1
This is the JS:
var API_KEY = 'b7290ac3-1f9f-4575-88a7-89fed0c61f7f',
MAIN_URL = 'http://api.skyscanner.net/api.ashx?key=' + API_KEY;
function main(){
console.log('loaded module');
var snippet = new skyscanner.snippets.SearchPanelControl();
snippet.setCurrency('GBP');
snippet.setDeparture('uk');
snippet.draw(document.getElementById('snippet_searchpanel'));
};
function newWrite(str) {
$(str).appendTo('body');
}
var oldWrite = document.write;
document.write = newWrite;
function onMainSkyscannerScriptLoad(e) {
console.log('loaded main script');
skyscanner.loadAndWait('snippets', '1', {'nocss' : true}, main);
}
$('button').click(function() {
console.log('getting main script');
$.getScript(MAIN_URL, onMainSkyscannerScriptLoad);
});
I also used this to personalise the widget:
skyscanner.load("snippets","2");
function main(){
var snippet = new skyscanner.snippets.SearchPanelControl();
snippet.setShape("box300x250");
snippet.setCulture("en-GB");
snippet.setCurrency("USD");
snippet.setColourScheme("classicbluelight");
snippet.setProduct("flights","1");
snippet.setProduct("hotels","2");
snippet.setProduct("carhire","3");
snippet.draw(document.getElementById("snippet_searchpanel"));
}
skyscanner.setOnLoadCallback(main);
Skyscanner B2B support engineer here. Are you still having trouble with this?
For the quickest response, please contact us here: http://business.skyscanner.net/portal/en-GB/Home/Contact
The first thing to check is that the file is on a web server (localhost is fine), and not loaded from the desktop (or local disk in general). This is because some of the Skyscanner JS code looks up other files using URLs like //api.skyscanner.net. In other words, saving the file to the desktop and opening it from there will not work (will show as an empty div). Here's the most basic example of drawing a widget. Can you try putting this in a file and accessing it through a server? If it works we can build on it :)
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" >
<head>
<script type="text/javascript" src="//api.skyscanner.net/api.ashx?key=b7290ac3-1f9f-4575-88a7-89fed0c61f7f"></script>
<script type="text/javascript">
skyscanner.load("snippets","2");
function main(){
var snippet = new skyscanner.snippets.SearchPanelControl();
snippet.setShape("box300x250");
snippet.setCulture("en-GB");
snippet.setCurrency("USD");
snippet.setProduct("flights","1");
snippet.setProduct("hotels","2");
snippet.setProduct("carhire","3");
snippet.draw(document.getElementById("snippet_searchpanel"));
}
skyscanner.setOnLoadCallback(main);
</script>
</head>
<body>
<div id="snippet_searchpanel" style="width: auto; height:auto;"></div>
</body>
</html>

Perform a function based on the hash with director.js

I am trying to use director.js for the routing on my single page application. The issue is when you go to a page by typing it into the address bar the application does not perform the function that the hash in the routing table is pointed to.
Here is the example on github - If I refresh the page with a hash or direct to a page with a hash nothing shows up in the console. But if I click on one of the links console output is shown. How can I change this code so that if a user directly goes to a link the routing table checks the hash and performs it's matching function from the routing table? Please answer with a methodology that utilizes director.js
<html>
<head>
<meta charset="utf-8">
<title>A Gentle Introduction</title>
<script src="https://raw.github.com/flatiron/director/master/build/director.min.js"></script>
<script>
var author = function () { console.log("author"); },
books = function () { console.log("books"); },
viewBook = function(bookId) { console.log("viewBook: bookId is populated: " + bookId); };
var routes = {
'/author': author,
'/books': [books, function() { console.log("An inline route handler."); }],
'/books/view/:bookId': viewBook
};
var router = Router(routes);
router.init();
</script>
</head>
<body>
<ul>
<li>#/author</li>
<li>#/books</li>
<li>#/books/view/1</li>
</ul>
</body>
</html>
I have not used Director but your issue may be the fact that GitHub serves the "raw" files with a mime type of "text/plain". So the Director js code might not be processed as javascript, causing your test page not to work. Try downloading your own copy of Director and link to the local version instead of the one on GitHub.

Categories