Trigger C# method from JavaScript and send parameters - c#

I'm trying to call a C# method from JavaScript and send parameters along with the call. I've done calls to web method but since I can't get to server side controls in static web method, I can't really use it in this case.
I can't do full postback because I need to get Google Map coordinates which in my case I'm accessing them this way, and I'm not able to access them differently:
var map = new google.maps.Map(document.getElementById("dvMap"), mapOptions);
var bounds = new google.maps.LatLngBounds();
bounds = map.getBounds();
var latLng = map.getCenter();
var latSW = bounds.getSouthWest().lat();
var lngSW = bounds.getSouthWest().lng();
var centerLat = latLng.lat();
var centerLng = latLng.lng();
So now since I want to pass some of these parameters to actual c# function it's ok even if I need to do full server side postback as long as I have the controls in my backend code.
Once on server side I need to populate asp.net repeater control with the dataset, that's the biggest issue why I need to trigger backend method.
public void GetData(string latSW, string lngSW, string latNE, string lngNE)
{
DataTable dt = this.GetData(latSW, lngSW, latNE, lngNE);
rptMarkers.DataSource = dt;
rptMarkers.DataBind();
RepDetails.DataSource = dt;
RepDetails.DataBind();
}

I'm unsure, from your question, whether you can or can't make a full post back so here's a fun javascript solution
function myawesomejavascriptfunction(latsw,lngsw,latne,lngne)
{
var myawesomeform=document.createElement('form');
myawesomeform.setAttribute('method','post");
myawesomeform.setAttribute('action','/myawesomewebendpoint');
var myawesomelatsw=document.createElement('input');
myawesomelatsw.setAttribute('type','hidden');
myawesomelatsw.setAttribute('name','latsw');
myawesomelatsw.setAttribute('value',latsw);
var myawesomelngsw=document.createElement('input');
myawesomelngsw.setAttribute('type','hidden');
myawesomelngsw.setAttribute('name','lngsw');
myawesomelngsw.setAttribute('value',lngsw);
var myawesomelatne=document.createElement('input');
myawesomelatne.setAttribute('type','hidden');
myawesomelatne.setAttribute('name','latne');
myawesomelatne.setAttribute('value',latne);
var myawesomelngne=document.createElement('input');
myawesomelngne.setAttribute('type','hidden');
myawesomelngne.setAttribute('name','lngne');
myawesomelngne.setAttribute('value',lngne);
document.getElementsByTagName('body')[0].appendChild(myawesomeform);
myawesomeform.submit();
}
The endpoint method at /myawesomewebendpoint will call the class with the GetData() method and pass on the parameters.
It will work, provided I've not got hold of the entirely wrong end of the stick.

Related

Twilio StatusCallback not working:

So I'm building an app with twilio voice, and I've got all the phonecall stuff working. But I'm having a little trouble understanding which parameters my callback should have.
I've registered the URL as described in the docs:
options.From = formatPhoneNumber(callout.callback_number);
options.To = formatPhoneNumber(offer.employee_phone_number);
options.Url = TwilioCallBotController.TwilioCalloutScriptURL;
options.StatusCallback = TwilioCallBotController.StatusCallbackURL;
options.StatusCallbackEvents = new []{"initiated", "ringing", "answered", "completed" };
options.StatusCallbackMethod = "POST";
I've also made a callback method here, but I'm not having much luck finding out how the parameters are supposed to work with their API. I'm kindof at a loss as to what could be the reason behind this one not working:
[HttpPost]
public ActionResult TwilioStatusCallback()
{
var twiml = new Twilio.TwiML.TwilioResponse();
twiml.Say("This is a test");
string CallSid = Request.Form["CallSid"];
string CallStatus = Request.Form["CallStatus"];
Debug.WriteLine("Status Callback Delivered");
Shift_Offer shoffer = db.Shift_Offers.Where(s => s.twillio_sid == CallSid).ToList()[0];
shoffer.status = CallStatus.ToString();// + DateTime.Now.ToString();
return TwiML(twiml);
}
Edit:
So it turns out that the API is very sensitive about the method signature (the call was previously throwing a method not found exception in a number of microsoft DLLs, including System.Web and System.Web.Mvc.
So I've actually gotten the software to call the method by using an empty method signature (no parameters).
However I'm still having trouble getting the parameters from the HTTPPOST
Edit: So upon further investigation I've managed to inspect the Request. The values I'm after exist in Request.Form["foo"], but they don't seem to be getting put into the two strings I have declared. I've removed the ["HttpPost"] attribute to try to troubleshoot the issue, but I'm really at a loss as to why I can see the values in the debugger, but they're not translating into memory.
public ActionResult TwilioStatusCallback()
{
var twiml = new Twilio.TwiML.TwilioResponse();
string sid = Request.Form["CallSid"];
string status = Request.Form["CallStatus"];
Shift_Offer shoffer = db.Shift_Offers.Where(s => s.twillio_sid == sid).ToList()[0];
shoffer.status = status;// + DateTime.Now.ToString();
return TwiML(twiml);
}
Last issue was that the database wasn't being saved.
Just added a db.SaveChanges() and we're good.

How to read something from a file with C# and use it with HTML codes on ASP.NET page?

I'm doing a school project, I need to make a simple web site, add google maps on it, read, lets say, 100 diffrent addresses from a text file and show those locations on google maps with markers.
Now I'm trying to add google maps to my ASP.net page with javascript which I saw on google maps tutorials. And there's that problem which I have to convert adresses to coordinates. So for that I'm using
function addAddressToMap(response) {
if (!response || response.Status.code != 200) {
alert("Sorry, we were unable to geocode that address");
}
else {
place = response.Placemark[0];
point = new GLatLng(place.Point.coordinates[1],place.Point.coordinates[0]);
marker = new GMarker(point);
map.addOverlay(marker);
marker.openInfoWindowHtml(place.address + '<br>' + '<b>Country code:</b> ' + place.AddressDetails.Country.CountryNameCode);
}
}
// showLocation() is called when you click on the Search button
// in the form. It geocodes the address entered into the form
// and adds a marker to the map at that location.
function showLocation() {
var address = "izmit";
var address2 = "ağrı";
geocoder.getLocations(address, addAddressToMap);
geocoder.getLocations(address2, addAddressToMap);
}
these functions and they are working fine. But my problem here is, I need to get these address informations from a text file. But to get them, I need to use a few diffrent codes. And I want to make it on the server side with C# codes. But I don't know how to write some codes on server side and then return something to HTML side as address. I hope you understand. Thank you for your helps.
Update:
Server code:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Page.ClientScript.RegisterArrayDeclaration("Skills", "'asa'");
Page.ClientScript.RegisterArrayDeclaration("Skills", "'bell'");
Page.ClientScript.RegisterArrayDeclaration("Skills", "'C'");
Page.ClientScript.RegisterArrayDeclaration("Skills", "'C++'");
}
}
Client side:
function showLocation()
{
var address = "izmit";
var address2 = "ağrı";
geocoder.getLocations(Skills[0], addAddressToMap);
}
Now if I use "asa" instead of Skills[0] it will show the location and mark, but with Skills[0] it's not working. And thank you for your answer that was what I'm looking for.
even if I try var MyValue = Skills[0]; and then use MyValue instead of Skills[0] it's still not working
If I understood your question correctly, you want to create an array on the server side and read it in the client.
See this link for a tutorial on how to pass an array from the server to the client.
Basically, you want to use the ClientScriptManager.RegisterArrayDeclaration method to add values to the array.
You can then easily read it in javascript.
Server Side:
string arrayName = "MyArray";
Page.ClientScript.RegisterArrayDeclaration(arrayName , "'value1'");
Page.ClientScript.RegisterArrayDeclaration(arrayName , "'value2'");
Javascript on Client Side:
function readArray()
{
for (var i = 0; i < MyArray.length; i++)
{
//Reading Element From Array
var myValue = MyArray[i];
}
}

Calling javascript object method using WebBrowser.Document.InvokeScript

In my WinForms application I need to call javascript function from my WebBrowser control. I used Document.InvokeScript and it works perfect with functions alone e.g
Document.InvokeScript("function").
But when i want to call javascript object method e.g.
Document.InvokeScript("obj.method")
it doesn't work. Is there a way to make it work? Or different solution to this problem? Without changing anything in the javascript code!
Thanks in advance :)
The example in the documentation does NOT include the parenthesis.
private void InvokeScript()
{
if (webBrowser1.Document != null)
{
HtmlDocument doc = webBrowser1.Document;
String str = doc.InvokeScript("test").ToString() ;
Object jscriptObj = doc.InvokeScript("testJScriptObject");
Object domOb = doc.InvokeScript("testElement");
}
}
Try
Document.InvokeMethod("obj.method");
Note that you can pass arguments if you use HtmlDocument.InvokeScript Method (String, Object[]).
Edit
Looks like you aren't the only one with this issue: HtmlDocument.InvokeScript - Calling a method of an object . You can make a "Proxy function" like the poster of that link suggests. Basically you have a function that invokes your object's function. It's not an ideal solution, but it'll definitely work. I'll continue looking to see if this is possible.
Another post on same issue: Using WebBrowser.Document.InvokeScript() to mess around with foreign JavaScript . Interesting solution proposed by C. Groß on CodeProject:
private string sendJS(string JScript) {
object[] args = {JScript};
return webBrowser1.Document.InvokeScript("eval",args).ToString();
}
You could make that an extension method on HtmlDocument and call that to run your function, only using this new function you WOULD include parenthesis, arguments, the whole nine yards in the string you pass in (since it is just passed along to an eval).
Looks like HtmlDocument does not have support for calling methods on existing objects. Only global functions. :(
Unfortunately you can't call object methods out of the box using WebBrowser.Document.InvokeScript.
The solution is to provide a global function on the JavaScript side which can redirect your call. In the most simplistic form this would look like:
function invoke(method, args) {
// The root context is assumed to be the window object. The last part of the method parameter is the actual function name.
var context = window;
var namespace = method.split('.');
var func = namespace.pop();
// Resolve the context
for (var i = 0; i < namespace.length; i++) {
context = context[namespace[i]];
}
// Invoke the target function.
result = context[func].apply(context, args);
}
In your .NET code you would use this as follows:
var parameters = new object[] { "obj.method", yourArgument };
var resultJson = WebBrowser.Document.InvokeScript("invoke", parameters);
As you mention that you cannot change anything to your existing JavaScript code, you'll have to inject the above JavaScript method in some how. Fortunately the WebBrowser control can also do for you by calling the eval() method:
WebBrowser.Document.InvokeScript("eval", javaScriptString);
For a more robust and complete implementation see the WebBrowser tools I wrote and the article explaining the ScriptingBridge which specifically aims to solve the problem you describe.
webBrowser.Document.InvokeScript("execScript", new object[] { "this.alert(123)", "JavaScript" })
for you supposed to be like this
webBrowser.Document.InvokeScript("execScript", new object[] { "obj.method()", "JavaScript" })

Persist data using JSON

I'm tryping to use JSON to update records in a database without a postback and I'm having trouble implementing it. This is my first time doing this so I would appreciate being pointed in the right direction.
(Explanation, irrelevant to my question: I am displaying a list of items that are sortable using a jquery plugin. The text of the items can be edited too. When people click submit I want their records to be updated. Functionality will be very similar to this.).
This javascript function creates an array of the objects. I just don't know what to do with them afterwards. It is called by the button's onClick event.
function SaveLinks() {
var list = document.getElementById('sortable1');
var links = [];
for (var i = 0; i < list.childNodes.length; i++) {
var link = {};
link.id = list.childNodes[i].childNodes[0].innerText;
link.title = list.childNodes[i].childNodes[1].innerText;
link.description = list.childNodes[i].childNodes[2].innerText;
link.url = list.childNodes[i].childNodes[3].innerText;
links.push(link);
}
//This is where I don't know what to do with my array.
}
I am trying to get this to call an update method that will persist the information to the database. Here is my codebehind function that will be called from the javascript.
public void SaveList(object o )
{
//cast and process, I assume
}
Any help is appreciated!
I have recently done this. I'm using MVC though it shouldn't be too different.
It's not vital but I find it helpful to create the contracts in JS on the client side and in C# on the server side so you can be sure of your interface.
Here's a bit of sample Javascript (with the jQuery library):
var item = new Item();
item.id = 1;
item.name = 2;
$.post("Item/Save", $.toJSON(item), function(data, testStatus) {
/*User can be notified that the item was saved successfully*/
window.location.reload();
}, "text");
In the above case I am expecting text back from the server but this can be XML, HTML or more JSON.
The server code is something like this:
public ActionResult Save()
{
string json = Request.Form[0];
var serializer = new DataContractJsonSerializer(typeof(JsonItem));
var memoryStream = new MemoryStream(Encoding.Unicode.GetBytes(json));
JsonItem item = (JsonItem)serializer.ReadObject(memoryStream);
memoryStream.Close();
SaveItem(item);
return Content("success");
}
Hope this makes sense.
You don't use CodeBehind for this, you use a new action.
Your action will take an argument which can be materialized from your posted data (which, in your case, is a JavaScript object, not JSON). So you'll need a type like:
public class Link
{
public int? Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Url { get; set; }
}
Note the nullable int. If you have non-nullable types in your edit models, binding will fail if the user does not submit a value for that property. Using nullable types allows you to detect the null in your controller and give the user an informative message instead of just returning null for the whole model.
Now you add an action:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult DoStuff(IEnumerable<Link> saveList)
{
Repository.SaveLinks(saveList);
return Json(true);
}
Change your JS object to a form that MVC's DefaultModelBinder will understand:
var links = {};
for (var i = 0; i < list.childNodes.length; i++) {
links["id[" + i + "]"] = list.childNodes[i].childNodes[0].innerText;
links["title[" + i + "]"] = list.childNodes[i].childNodes[1].innerText;
links["description[" + i + "]"] = list.childNodes[i].childNodes[2].innerText;
links["url[" + i + "]"] = list.childNodes[i].childNodes[3].innerText;
}
Finally, call the action in your JS:
//This is where I don't know what to do with my array. Now you do!
// presumes jQuery -- this is much easier with jQuery
$.post("/path/to/DoStuff", links, function() {
// success!
},
'json');
Unfortunately, JavaScript does not have a built-in function for serializing a structure to JSON. So if you want to POST some JSON in an Ajax query, you'll either have to munge the string yourself or use a third-party serializer. (jQuery has a a plugin or two that does it, for example.)
That said, you usually don't need to send JSON to the HTTP server to process it. You can simply use an Ajax POST request and encode the form the usual way (application/x-www-form-urlencoded).
You can't send structured data like nested arrays this way, but you might be able to get away with naming the fields in your links structure with a counter. (links.id_1, links.id_2, etc.)
If you do that, then with something like jQuery it's as simple as
jQuery.post( '/foo/yourapp', links, function() { alert 'posted stuff' } );
Then you would have to restructure the data on the server side.

C# class objects

I have a class that I am using below. And I am using this class for my windows application. However, when I call the method from my application ReadInConfig() it successfully reads and fills the datatable, and assigns the _sip_ip address.
In my windows application I have the following. However, it doesn't give me the sip_ip that it has been assigned.
ConfigSIP readIn = new ConfigSIP();
readIn.ReadInConfig();
string sip_ip = readIn.sip_ip(); // Get nothing here.
I am thinking as the _sip_ip that has been assigned by the data table is a different object than doing this readIn.sip_ip();
Is there any way I can solve this problem?
Many thanks,
public class ConfigSIP
{
private string _sip_ip;
// Fill the data table and assign the sip ip.
public void ReadInConfig()
{
DataTable dt = new DataTable("Admin");
dt.ReadXmlSchema(#"C:\Config.xml");
dt.ReadXml(#"C:\Config.xml");
_sip_ip = dt.Rows[0]["Sip_ip"].ToString();
}
// Return the sip ip address.
public string sip_ip()
{
return _sip_ip;
}
}
You forgot to call ReadInConfig:
ConfigSIP readIn = new ConfigSIP();
readIn.ReadInConfig();
string sip_ip = readIn.sip_ip();
If your code is copied verbatim your client code isn't calling the ReadInConfig() method. So the string will never get populated.

Categories

Resources