How to Call JavaScript Function in Controller mvc - asp.net-mvc-4

I have one javascript function which is writted in view and i want call that function in Controller.the javascript takes input parameter and return one result. i have to store that value in string or variable.can anyone please help me in this.thanks in advance.here i mentioned my sample JavaScript here,
function GetLong(address) {
var geocoder = new google.maps.Geocoder();
geocoder.geocode({ 'address': address }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
long = results[0].geometry.location.lng();
} else {
alert("Request failed.")
}
});
return long;
};

The purpose of the MVC framework is to seperate Model, View and Controller. You can't invoke a javascript code from the MVC-Controller since the view is rendered and displayed in the client browser. You can invoke the javascript code in the view and send a POST or GET request to your Server for if you need a dynamic comunication between your view and controller.
If you want to use that javascript code in C# for example you might want to have a look at this https://github.com/jonsagara/geocodingapi
Or this Answer might be helpful aswell Google Maps v3 geocoding server-side

Related

Cannot redirect another page in ASP.NET Core MVC project Controller

I would like to press a button to connect a GET api, do something and redirect the page.
const Http = new XMLHttpRequest();
Http.open("GET", '/Startup/Action/Test');
Http.send();
Http.onreadystatechange = (e) => {
console.log(Http.responseText)
}
Then in my Controller:
[HttpGet("Startup/Action/{Handle}")]
public IActionResult Action(string Handle)
{
this.ViewData["Result"] = Handle;
return this.Ok(Handle);
// return LocalRedirect("~/Startup/");
// return Redirect("http://localhost:50429/");
// return View("~/Views/Startup/Index.cshtml");
// return Redirect("/");
// return RedirectToAction("Index", "Startup");
}
I get response and see it in console written by the javascript XMLHttpRequest event. However I cannot redirect to just another page. I tried all options commented above as return value.
With AJAX you don't perform the redirect server-side, you perform it client-side after the result has been received. Something like this:
Http.onreadystatechange = (e) => {
if(xhr.readyState === 4 && xhr.status === 200) {
window.location.href = '#Url.Action("Index", "Startup")';
} else {
// non-success reaponse? do something else?
}
}
The above code would redirect following a successful AJAX response. Note that this JavaScript code would need to be on a view itself in order to use the Url.Action() helper. If the JavaScript code is in a separate file, one option could be to return as a string in the AJAX response the URL to which you are redirecting.
Note however that what you are doing is a bit different here:
this.ViewData["Result"] = Handle;
I could be wrong, but I suspect this won't carry over on a redirect. TempData might? But ultimately the question then becomes... What exactly are you trying to accomplish? You are sending a value to the server and then trying to redirect the user to another page to include that value. Well, the client already knows that value, and since it's AJAX the client needs to perform the redirect, so is this AJAX operation even necessary at all?
It's not entirely clear to me what the overall goal here is, and I suspect the overall setup could be simplified significantly. But it looks like AJAX is needed at all here. You can revert your server-side code to performing the redirect and, instead of using AJAX, just redirect the client to that server-side action entirely:
window.location.href = '/Startup/Action/Test';
or:
winfow.location.href = '#Url.Action("Action", "Startup", new { Handle = "Test" })';
And then redirect in your server-side action as you originally tried:
[HttpGet("Startup/Action/{Handle}")]
public IActionResult Action(string Handle)
{
this.ViewData["Result"] = Handle;
return RedirectToAction("Index", "Startup");
}
It's still possible, and again I'm not certain, that ViewData isn't correct here and you may want to use TempData on a redirect. Though, again, it's equally likely that whatever you're trying to accomplish can be done so more effectively in the first place. Such as skipping this Action action method entirely and just passing the Handle value directly to the Index action, whatever it does it with that value.

Having trouble making a OAuth 1.0a signed request to the Tumblr API using HelloJS

I'm trying to interface with the Tumblr API to pull a list of followers. I'm brand new the whole OAuth thing, so I was trying to model my calls off the demos at https://adodson.com/hello.js/demos/tumblr.html . Unfortunately, the example they give only requires the API key for identification (https://www.tumblr.com/docs/en/api/v2#posts) where as getting the followers needs a signed OAuth request (https://www.tumblr.com/docs/en/api/v2#followers).
The call I'm using is:
function getFollowers(blog){
hello('tumblr').api('blog/'+blog+'/followers/').then(function(r){
console.log("r", r);
//Bellow here not really relevant
var a = r.data.map(function(item){
return "<h2>"+item.title+"</h2>"+item.body_abstract;
});
document.getElementById('blogs').innerHTML = a.join('');
});
}
This generates the request url from the proxy:
https://auth-server.herokuapp.com/proxy?path=https%3A%2F%2Fapi.tumblr.com%2Fv2%2Fblog%2Fnmlapp.tumblr.com%2Ffollowers%2F%3Fapi_key%3DREDACTED08u%26callback%3D_hellojs_9kvqxi31&access_token=&then=redirect&method=get&suppress_response_codes=truee
and Tumblr's API returns
_hellojs_9kvqxi31({"meta":{"status":401,"msg":"Not Authorized"},"response":[]});
I can see that the login call has all of the OAuth info in the Query String Parameters field, and the one I'm trying to make does not, but I'm not sure what the right way to include that through helloJS is.
Got it, the function had to be wrapped in the login method. This was shown in the other example, but the way that it called parameters from the api object had me confused.
function doTheThing(network){
hello( network ).login({force:false}).then( function(r){
hello('tumblr').api('followers').then(function(r){
console.log("r", r);
var a = r.data.map(function(item){
return "<h2>"+item.title+"</h2>"+item.body_abstract;
});
document.getElementById('blogs').innerHTML = a.join('');
});
});
}
//...
tumblr:{
get: {
//...
//This next part needs to be generated dynamically, but you get the idea
'followers': 'blog/BLOGNAME.tumblr.com/followers',
}
callback(p.path);
}
},
post: {
//...
'followers': function(p, callback) {
p.path = 'followers';
query(p, callback);
}
},

Meteor.http.get issue with Twitter API

I am using Meteor and the Twitter API for a project. I want to get information on a user from Twitter. I wrote a function that for example returns only the location of a user from Twitter. I believe this is the proper way to do a request on Meteor. Here it is :
Meteor.methods({getTwitterLocation: function (username) {
Meteor.http.get("https://api.twitter.com/1/users/show.json?screen_name="+ username +"&include_entities=true", function(error, result) {
if (result.statusCode === 200) {
var respJson = JSON.parse(result.content);
console.log(respJson.location);
console.log("location works");
return (respJson.location)
}else {
return ( "Unknown user ")
}
});
}});
Now this function will log what's in the console on my Git Bash. I get someones Location by doing a Meteor.call. But I want to post what that function returns on a page. In my case, I want to post in on a user's profile. This doesn't work. But the console.log(respJson.location) returns the location in my Git Bash but it won't display anything on the profile page. This is what I did on my profile page:
profile.js :
Template.profile.getLocation= function(){
return Meteor.call("getTwitterLocation","BillGates");
}
profile.html :
<template name="profile">
from {{getLocation}}
</template>
With that I get "Seattle, WA" and " "location works" on my Git Bash but nothing on the profile page. If anyone knows what I can do, that'd be really appreciated. Thanks.
Firstly when data is returned from the server you need to use a synchronous call, as the callback will return the data when the server already thinks the meteor method has completed. (the callback will be fired at a later time, when the data is returned from the server, by which time the meteor client would have already got a response)
var result = Meteor.http.get("https://api.twitter.com/1/users/show.json?screen_name="+ username +"&include_entities=true");
if (result.statusCode === 200) {
var respJson = JSON.parse(result.content);
console.log(respJson.location);
console.log("location works");
return (respJson.location)
}else {
return ( "Unknown user ")
}
The second is you need to use a Session hash to return the data from the template. This is because it will take time to get the response and the getLocation would expect an instant result (without a callback). At the moment client side javascript can't use synchronous api calls like on the server.
Template.profile.getLocation= function(){
return Session.get("twitterlocation");
}
Use the template created event to fire the meteor call:
Template.profile.created = function() {
Meteor.call("getTwitterLocation","BillGates", function(err,result) {
if(result && !err) {
Session.set("twitterlocation", result);
}
else
{
Session.set("twitterlocation", "Error");
}
});
});
Update:
Twitter has since updated its API to 1.1 a few modifications are required:
You now need to swap over to the 1.1 api by using 1.1 instead of 1. In addition you need to OAuth your requests. See https://dev.twitter.com/docs/auth/authorizing-request. Below contains sample data but you need to get proper keys
var authkey = "OAuth oauth_consumer_key="xvz1evFS4wEEPTGEFPHBog",
oauth_nonce="kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg",
oauth_signature="tnnArxj06cWHq44gCs1OSKk%2FjLY%3D",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp=""+(new Date().getTime()/1000).toFixed(0)+"",
oauth_token="370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb",
oauth_version="1.0"";
Be sure to remove the newlines, I've wrapped it to make it easy to read.
var result = Meteor.http.get("https://api.twitter.com/1.1/users/show.json?screen_name="+ username +"&include_entities=true",{headers:{Authorization : authkey});
If you find this a bit troublesome it might be easier to just use a package like https://github.com/Sewdn/meteor-twitter-api via meteorite to OAuth your requests for you.

Dojo datagrid jsonrest response headers

I'd like to use custom headers to provide some more information about the response data. Is it possible to get the headers in a response from a dojo datagrid hooked up to a jsonRest object via an object store (dojo 1.7)? I see this is possible when you are making the XHR request, but in this case it is being made by the grid.
The API provides an event for a response error which returns the response object:
on(this.grid, 'FetchError', function (response, req) {
var header = response.xhr.getAllResponseHeaders();
});
using this I am successfully able to access my custom response headers. However, there doesn't appear to be a way to get the response object when the request is successful. I have been using the undocumented private event _onFetchComplete with aspect after, however, this does not allow access to the response object, just the response values
aspect.after(this.grid, '_onFetchComplete', function (response, request)
{
///unable to get headers, response is the returned values
}, true);
Edit:
I managed to get something working, but I suspect it is very over engineered and someone with a better understanding could come up with a simpler solution. I ended up adding aspect around to allow me to get hold of the deferred object in the rest store which is returned to the object store. Here I added a new function to the deffered to return the headers. I then hooked in to the onFetch of the object store using dojo hitch (because I needed the results in the current scope). It seems messy to me
aspect.around(restStore, "query", function (original) {
return function (method, args) {
var def = original.call(this, method, args);
def.headers = deferred1.then(function () {
var hd = def.ioArgs.xhr.getResponseHeader("myHeader");
return hd;
});
return def;
};
});
aspect.after(objectStore, 'onFetch', lang.hitch(this, function (response) {
response.headers.then(lang.hitch(this, function (evt) {
var headerResult = evt;
}));
}), true);
Is there a better way?
I solved this today after reading this post, thought I'd feed back.
dojo/store/JsonRest solves it also but my code ended up slightly different.
var MyStore = declare(JsonRest, {
query: function () {
var results = this.inherited(arguments);
console.log('Results: ', results);
results.response.then(function (res) {
var myheader = res.xhr.getResponseHeader('My-Header');
doSomethingWith(myheader);
});
return results;
}
});
So you override the normal query() function, let it execute and return its promise, and attach your own listener to its 'response' member resolving, in which you can access the xhr object that has the headers. This ought to let you interpret the JsonRest result while fitting nicely into the chain of the query() all invokers.
One word of warning, this code is modified for posting here, and actually inherited from another intermediary class that also overrode query(), but the basics here are pretty sound.
If what you want is to get info from the server, also a custom key-value in the cookie can be a solution, that was my case, first I was looking for a custom response header but I couldn't make it work so I did the cookie way getting the info after the grid data is fetched:
dojo.connect(grid, "_onFetchComplete", function (){
doSomethingWith(dojo.cookie("My-Key"));
});
This is useful for example to present a SUM(field) for all rows in a paginated datagrid, and not only those included in the current page. In the server you can fetch the COUNT and the SUM, the COUNT will be sent in the Content-Range header and the SUM can be sent in the cookie.

Node.js prevent function inspection (toString)

When javascript is run in the browser there is no need to try and hide function code because it is downloaded and viewable in source.
When run on the server the situation changes. There are use cases such as api where you want to provide users with functions to call without allowing them to view the code that which is run.
On our specific case we want to execute user submitted javascript inside node. We are able to sandbox node.js api however we would like to add our own api to this sandbox without users being able to toString the function to view the code which is run.
Does anyone have a pattern or know of a way of preventing users from outputting a functions code?
Update:
Here is a full solution (i believe) based on the accepted answer below. Please note that although this is demonstrated using client side code. You would not use this client side as someone can see the contents of your hidden function by simply reading the downloaded code (although it may provide some basic slow down to inspect the code if you have used a minify).
This is meant for server side use where you want to allow users to run api code within a sandbox env but not allow them to view what the api's do. The sandbox in this code is only to demonstrate the point. It is not an actual sandbox implementation.
// function which hides another function by returning an anonymous
// function which calls the hidden function (ie. places the hidden
// function in a closure to enable access when the wraped function is passed to the sandbox)
function wrapFunc(funcToHide) {
var shownFunc = function() {
funcToHide();
};
return shownFunc;
}
// function whose contents you want to hide
function secretFunc() {
alert('hello');
}
// api object (will be passed to the sandbox to enable access to
// the hidden function)
var apiFunc = wrapFunc(secretFunc);
var api = {};
api.apiFunc = apiFunc;
// sandbox (not an actual sandbox implementation - just for demo)
(function(api) {
console.log(api);
alert(api.apiFunc.toString());
api.apiFunc();
})(api);
If you wrap a callback in a function, you can use another function in that scope which is actually hidden from the callback scope, thus:
function hideCall(funcToHide) {
var hiddenFunc = funcToHide;
var shownFunc = function() {
hiddenFunc();
};
return shownFunc;
}
Then run thusly
var shtumCallBack = hideCall(secretSquirrelFunc);
userCode.tryUnwindingThis(shtumCallBack);
The userCode scope will not be able to access secretSquirrelFunc except to call it, because the scope it would need is that of the hideCall function which is not available.