Specified cast is not valid when invoking javascript function in webbrowser - javascript

I'm trying to invoke javascript function in webbrowser.
Website have separate file with javascript functions.
This is a part of website html file:
<div class="header">
<a class="buttonrg" onclick="$(this).hide();remove('56442741')"> Remove </a>
</div>
This is remove function from .js file:
function remove(id) {
$.ajax({
type: "POST",
url: "ajax/remove.php",
data: "remove=" + id
});
}
And I'm trying to call 'remove' function with this script in c#:
public void RemoveOffer(int _id)
{
try
{
webBrowser.Document.InvokeScript("remove", new object[] { _id.ToString() });
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
but always when I'm trying to call this script console is showing me an error: specified cast is not valid.
What could went wrong?

Change data: "remove=" + remove to data: { "remove": id }

Are you calling the InvokeScript() from a thread other than the one that created it? Doing this caused this exception to be thrown for me.
It's a strange error message given the circumstances, however I resolved this with an Invoke()
e.g.
private void RemoveOffer(int _id)
{
if (webBrowser.InvokeRequired)
{
webBrowser.Invoke(new Action(() => { RemoveOffer(_id); }));
return;
}
webBrowser.Document.InvokeScript("remove", new object[] { _id }); // Not sure if the .ToString() is required...
}

Related

Trigger a JavaScript function on a WebView in Flutter

I have a webpage that I load on a WebViw in flutter and that webpage has a javascript function that I want to run with a parameter from flutter.
I wrote this uderneath, and it looks like it is running the alert function fine, but when I try to run the function that is defined on the webpage javascript it says it is undefined. Why could this be? Also, do you see any other mistakes on my code that I may be missing, despite it working?
class WebViewPageState extends State<WebViewPage> {
final String url;
final String title;
WebViewPageState(this.url, this.title);
final Completer<WebViewController> _controller = Completer<WebViewController>();
late WebViewController _mycontroller;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.title),
),
body: Column(children: [
Expanded(
child: WebView(
initialUrl: this.url,
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webviewcontroller) {
_controller.complete(_mycontroller = webviewcontroller);
},
onPageFinished: (url){
print("Ok we loaded page");
setState(() {
_mycontroller.runJavascriptReturningResult('alert("Hello, World!")');
});
},
))
]));
}
}
runJavascriptReturningResult is trying to get a return value from your javascript and since it's an alert it can't find it. try using _mycontroller.runJavascript('alert("Hello, World!")');

How can I use c# asp.net to get data from url?

I'm trying to get some info I sent by form to angularJS in my c# asp.net backend, and I'm having trouble doing it.
Visual Studio won't let me compile because it says:
Error CS0120: an object reference is required for the nonstatic field, method, or property 'member'
That's is my controller
public class SearchController : ApiController
{
public string Get()
{
string test = HttpContext.Request.QueryString["txt_search"];
return test;
}
}
Here's what I got in my angularjs:
$scope.sendForm = function () {
console.log($scope.model.search);
$http({
method: 'GET',
url: '/api/search?txt_search=' + $scope.model.search
})
.then(function () {
console.log('sucesso a executar o post');
}, function () {
console.log('Erro ao executar o post');
});
};
As suggested in the comments, you should just be able to change your method definition and skip this altogether:
public string Get(string txt_search)
{
return txt_search;
}
Alternatively, to reference the current request, I believe you need to use the following (note the addition of .Current):
string test = HttpContext.Current.Request.QueryString["txt_search"];
The reason is that HttpContext defines Request as an instance property. The only public static property is Current, which returns an instance of HttpContext through which you can reach Request.
Welcome to Stack Overflow,
Your Angular code is correct
You need to pass a parameter on server side to collect txt_search value
Here it is:
[HttpGet]
[Route("/api/search")]
public string mySearchMethod(string txt_search)
{
//something here with txt_search
return "OK";
}
Both of the above solution will work, but for another approach as you are using asp.net web api and router you can make it as below as well
In your Angular code, simple pass the search as below
```
$scope.sendForm = function () {
console.log($scope.model.search);
$http({
method: 'GET',
url: '/api/search/'+ $scope.model.search
})
.then(function () {
console.log('sucesso a executar o post');
}, function () {
console.log('Erro ao executar o post');
});
};
```
Notice
url: '/api/search/'+ $scope.model.search
and change the Action method as below
```
[HttpGet]
[Route("/api/search/{txt_search}")]
public string mySearchMethod(string txt_search)
{
//something here with txt_search
return "OK";
}
```
by doing this you don't have to worry about the name of the parameter txt_search
whatever you mention in route [Route("/api/search/{txt_search}")], you will get the value in same parameter.

Make Ajax call to C# Controller Method

This is the code in my javascript file called "data handling.js" located in a folder called "JS":
document.getElementById('submit-new-project').addEventListener("click", function () {
var ProjectName = document.getElementById('new-project').value;
if (ProjectName) {
$.ajax({
type: "POST",
url: "Controllers/HomeController/AddProject",
data: {"ProjectName": ProjectName},
success: function () {
hideElement("add-button-popup");
location.reload();
},
error: function (errorThrown) {
console.log(errorThrown)
}
});
}
else {
alert("Text Field Must Not Be Empty");
}
})
And here is my controller method:
public partial class HomeController : Controller
{
[HttpPost]
public static void AddProject(string ProjectName)
{
using (AutomationMethodDirectoryEntities db = new AutomationMethodDirectoryEntities())
{
try
{
PROJECT project = new PROJECT();
project.ProjectName = ProjectName;
db.PROJECTS.Add(project);
db.SaveChanges();;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}
The controller method is located in "Adders.cs" which is a partial class to "HomeController.cs" in the "Controllers" folder. Both the "JS" and "Controllers" folders are at the root level of the project. I have tried many variations of this ajax call and my biggest problem is with the URL. No matter what I try, I am always getting a 404 error because the server can't find the requested URL.
I've tried changing it to:
url: "Controllers/HomeController/AddProject"
url: "/Controllers/HomeController/AddProject"
url: "../Controllers/HomeController/AddProject"
url: "Home/AddProject"
url: "/Home/AddProject"
url: "../Home/AddProject"
url: "#(Url.Action(AddProject, HomeController))"
And I've swapped "HomeController" with "Adders" in different variations.
What am I doing wrong?
Is there anything I need to add/change to my controller method?
EDIT
Here is my "RouteConfig.cs" that I haven't made any changes to yet:
namespace RTCAD
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}
When calling your AddProject action, ASP.NET MVC creates an instance of the controller (using ControllerFactory), and since your method is static, it is not related to any instance, and thus, it will not be called by MVC.
Remove the static from the method declaration and use /Home/AddProject as the URL.

Pass complex parameter to Web API service via javascript

I'm making an ASP.NET Web API web service, and an HTML/javascript page to test it. The issue I'm having is with passing a complex data parameter and having it come through properly in the web API controller.
I know there are numerous similar questions and I've read them and tried the solutions and haven't solved it. I have also read some JQuery documentation.
Here's my controller:
public class TitleEstimateController : ApiController
{
public IHttpActionResult GetTitleEstimate([FromUri] EstimateQuery query)
{
// All the values in "query" are null or zero
// Do some stuff with query if there were anything to do
}
}
public class EstimateQuery
{
// Various fields
}
The route mapping in WebApiConfig.cs:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{query}"
);
And the javascript:
var uri = 'api/titleEstimate/';
var query = {
"username": $("#user").val(),
// other fields
};
$.getJSON(uri,query)
.done(function (data) {
$('#product').text("OK");
})
.fail(function (jqXHR, textStatus, err) {
$('#product').text('Error: ' + err);
});
Currently I'm getting a 404. I tried $.getJSON(uri + '/' + query) but that didn't work either. Before I was passing this object I was calling it successfully so I think the routing is generally OK. I tried a type converter, but that didn't help, still a 404. Does anyone see what I'm missing/doing wrong?
Answer
You are using the wrong uri. You need api/titleEstimate/getTitleEstimate. That explains and will resolve your 404.
Answer to Follow Up Question
Everything else you're doing almost works. After you resolve the 404, you'll find that you aren't receiving the value FromUri, and you'll have a follow up question. So, you need to change your route config to this:
config.Routes.MapHttpRoute(
name: "Default",
routeTemplate: "api/{controller}/{action}"
);
Then you'll not only resolve your 404 but also receive the FromUri value that you're sending as query string parameters.
Demo
Here is a fiddle for evidence, which is calling into this controller, which is hosted LIVE here. The only thing I changed in the working version are the uri to resolve the 404 and the route config to make sure you receive the FromUri value. That's all.
HTML
<label>Username:
<input id="user" />
</label>
<button id="submit">Submit</button>
<button id="submit-fail">Submit Fail</button>
<div id="product"></div>
JavaScript
This will succeed.
Note, we only need domain because we doing cross-site scripting here for the demo purpose.
var domain = "https://cors-webapi.azurewebsites.net";
$("#submit").click(function () {
var uri = domain + '/api/titleEstimate/getTitleEstimate';
var query = {
"username": $("#user").val(),
// other fields
};
$.getJSON(uri, query)
.done(function (data) {
$('#product').text(data);
})
.fail(function (jqXHR, textStatus, err) {
$('#product').text('Error: ' + err);
});
});
This will 404.
$("#submit-fail").click(function () {
var uri = domain + '/api/titleEstimate';
var query = {
"username": $("#user").val(),
// other fields
};
$.getJSON(uri, query)
.done(function (data) {
$('#product').text(data);
})
.fail(function (jqXHR, textStatus, err) {
$('#product').text('Error: ' + err);
});
});
Controller
public class TitleEstimateController : ApiController
{
public class EstimateQuery
{
public string username { get; set; }
}
public IHttpActionResult GetTitleEstimate([FromUri] EstimateQuery query)
{
// All the values in "query" are null or zero
// Do some stuff with query if there were anything to do
if(query != null && query.username != null)
{
return Ok(query.username);
}
else
{
return Ok("Add a username!");
}
}
}
You can read more details about WebApi routing here. From reading it you can probably come up with an alternative solution within your route config. There are also lots of terrific examples in this blog post.
First, I would try to use the attribute routing feature of web.api like this:
[RoutePrefix("api/titleestimate")]
public class TitleEstimateController : ApiController
{
[HttpGet]
public IHttpActionResult GetTitleEstimate([FromUri] EstimateQuery query)
{
// All the values in "query" are null or zero
// Do some stuff with query if there were anything to do
}
}
It would also be helpful to see the request in your dev tools. I disagree with Colin that you should make this a POST, because HTTP POST is supposed to be used to create new items. You are trying to get information so HTTP GET makes sense.
I think Web.Api assumes methods are GETs by default, but declarating it with the HttpGet attribute will for sure take care of that.
For complex objects, I usually send them in the message body rather than the URL.
Would you have any objection to an approach similar to the answer of this question?
How to pass json POST data to Web API method as object
It seems like the more straightforward/natural approach.
Something like (untested, but should be close):
[RoutePrefix("api/titleestimate")]
public class TitleEstimateController : ApiController
{
[HttpGet]
public IHttpActionResult GetTitleEstimate([FromBody] EstimateQuery query)
{
// All the values in "query" are null or zero
// Do some stuff with query if there were anything to do
}
}
public class EstimateQuery
{
public string QueryName{ get; set; }
public string Whatever{ get; set; }
}
$(function () {
var query = {QueryName:"My Query",Whatever:"Blah"};
$.ajax({
type: "GET",
data :JSON.stringify(query),
url: "api/titleEstimate",
contentType: "application/json"
})
.done(function (data) {
$('#product').text("OK");
})
.fail(function (jqXHR, textStatus, err) {
$('#product').text('Error: ' + err);
});
});

Meteor - How to find out if Meteor.user() can be used without raising an error?

I'm looking for a way to determine if Meteor.user() is set in a function that can be called both from the server and client side, without raising an error when it is not.
In my specific case I use Meteor server's startup function to create some dummy data if none is set. Furthermore I use the Collection2-package's autoValue -functions to create some default attributes based on the currently logged in user's profile, if they are available.
So I have this in server-only code:
Meteor.startup(function() {
if (Tags.find().fetch().length === 0) {
Tags.insert({name: "Default tag"});
}
});
And in Tags-collection's schema:
creatorName: {
type: String,
optional: true,
autoValue: function() {
if (Meteor.user() && Meteor.user().profile.name)
return Meteor.user().profile.name;
return undefined;
}
}
Now when starting the server, if no tags exist, an error is thrown: Meteor.userId can only be invoked in method calls. Use this.userId in publish functions.
So in other words calling Meteor.user() on the server startup throws an error instead of returning undefined or null or something. Is there a way to determine whether it will do so prior to calling it?
I cannot solve this simply by wrapping the call with if (Meteor.isServer) within the autoValue function, as the autoValue functions are normally called from server side even when invoked by the user, and in these cases everything in my code works fine.
Note that this is related to How to get Meteor.user() to return on the server side?, but that does not address checking if Meteor.user() is available in cases where calling it might or might not result in an error.
On the server, Meteor.users can only be invoked within the context of a method. So it makes sense that it won't work in Meteor.startup. The warning message is, unfortunately, not very helpful. You have two options:
try/catch
You can modify your autoValue to catch the error if it's called from the wrong context:
autoValue: function() {
try {
var name = Meteor.user().profile.name;
return name;
} catch (_error) {
return undefined;
}
}
I suppose this makes sense if undefined is an acceptable name in your dummy data.
Skip generating automatic values
Because you know this autoValue will always fail (and even if it didn't, it won't add a useful value), you could skip generating automatic values for those inserts. If you need a real name for the creator, you could pick a random value from your existing database (assuming you had already populated some users).
Been stuck with this for two days, this is what finally got mine working:
Solution: Use a server-side session to get the userId to prevent
"Meteor.userId can only be invoked in method calls. Use this.userId in publish functions."
error since using this.userId returns null.
lib/schemas/schema_doc.js
//automatically appended to other schemas to prevent repetition
Schemas.Doc = new SimpleSchema({
createdBy: {
type: String,
autoValue: function () {
var userId = '';
try {
userId = Meteor.userId();
} catch (error) {
if (is.existy(ServerSession.get('documentOwner'))) {
userId = ServerSession.get('documentOwner');
} else {
userId = 'undefined';
}
}
if (this.isInsert) {
return userId;
} else if (this.isUpsert) {
return {$setOnInsert: userId};
} else {
this.unset();
}
},
denyUpdate: true
},
// Force value to be current date (on server) upon insert
// and prevent updates thereafter.
createdAt: {
type: Date,
autoValue: function () {
if (this.isInsert) {
return new Date;
} else if (this.isUpsert) {
return {$setOnInsert: new Date};
} else {
this.unset();
}
},
denyUpdate: true
},
//other fields here...
});
server/methods.js
Meteor.methods({
createPlant: function () {
ServerSession.set('documentOwner', documentOwner);
var insertFieldOptions = {
'name' : name,
'type' : type
};
Plants.insert(insertFieldOptions);
},
//other methods here...
});
Note that I'm using the ff:
https://github.com/matteodem/meteor-server-session/ (for
ServerSession)
http://arasatasaygin.github.io/is.js/ (for is.existy)

Categories