Reading XML data from ASMX webservice for Jquery autocomplete - c#

Me and ASMX web services do not get on. We argue. She brings up arguments we had in the past. It's a pain. Our relationship is on the rocks!
I have an ASMX web service, which I haven't serialised with the Newtonsoft library (as explained why here: http://encosia.com/2011/04/13/asp-net-web-services-mistake-manual-json-serialization/). It looks like this:
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string[] GetCitiesWithState(string isoalpha2, string prefixText)
{
var dict = AtomicCore.CityObject.GetCitiesInCountryWithStateAutocomplete(isoalpha2, prefixText);
string[] cities = dict.Values.ToArray();
return cities;
}
Simple enough right? It return this when searching for new:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/">
<string>New Orleans, Louisiana</string>
<string>New York, New York</string>
</ArrayOfString>
I was expecting JSON, but after a bit of reading, it seems I shouldn't try and serialise the output - it should just happen right? Anyway, so I have the following JQuery on the frontend:
$('#<%=txtCity.ClientID%>').autocomplete('<%=ResolveUrl("~/AtomicService/Assets.asmx/GetCitiesWithState")%>', {
dataType: 'json',
httpMethod: 'POST',
contentType: 'application/json; charset=utf-8',
parse: function (data) {
var rows = new Array();
for (var i = 0; i < data.d.length; i++) {
rows[i] = { data: data.d[i], value: data.d[i].Value, result: data.d[i].Value };
}
return rows;
},
formatItem: function (row, i, n) {
return row.Value;
},
extraParams: {
minChars: 2,
isoalpha2: '<%=Session["BusinessCountry"].ToString()%>',
maxRows: 20,
prefixText: function () {
return $('#<%=txtCity.ClientID%>').val()
}
},
max: 20
}).result(function (event, data, formatted) {
if (data) {
alert(data['Key']);
}
});
I can see the calls using Chrome:
And yet stuff all happens! There is no Jquery errors, no fireworks, no anything. She is ignoring me.
At first I was blaming the webservice, but I think this may have more to do with how I'm parsing and formatting the data in jquery.
So, my question is, what am I doing wrong and how can I make the autocomplete work correctly?
Help appreciated :)
EDIT: It may not be helpful, but this is what I see in Fiddler:

The jQuery UI autocomplete does not anymore use the formatItem method. That and many other such methods were present in autocomplete's earlier version that was a plugin here
I have rewritten your code using the jQuery UI's autocomplete and it works for me with the below htm and asmx files.
Refer to the demos on the jQueryUI autocomplete for more methods you could use.
I have used the json2.min.js from www.json.org
Also I have added the [System.Web.Script.Services.ScriptService] attribute to the Service1 class so that it could directly be invoked from jQuery as a json web service.
These articles helped me:
ASMX and JSON – Common mistakes and misconceptions
Using jQuery to Consume ASP.NET JSON Web Services
3 mistakes to avoid when using jQuery with ASP.NET AJAX
The htm file
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>jQuery to ASMX</title>
<link rel="Stylesheet" type="text/css"
href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/themes/cupertino/jquery-ui.css"/>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<script type="text/javascript"
src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.min.js"></script>
<script type="text/javascript" src="http://localhost/Scripts/json2.min.js"></script>
</head>
<body>
<script type="text/javascript">
$(document).ready(function() {
$("#txtInput").autocomplete({
source:function (request, response) {
var paramters = {
isoalpha2: '<%=Session["BusinessCountry"].ToString()%>',
prefixText: request.term
};
$.ajax({
url: 'Service1.asmx/GetCitiesWithState',
type: 'POST',
dataType: 'json',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(paramters),
success: function(data) {
response($.each(data.d, function(index, value) {
return {
label: value,
value: index
}
}));
}
});
},
minLength:2,
delay:500
});
});
</script>
<p>
Hello, World!</p>
<label for="txtInput">
Enter the string here:</label><input type="text" id="txtInput"/>
</body>
</html>
The asmx file
using System.Web.Script.Services;
using System.Web.Services;
namespace jQueryAutoCompleteBackEnd
{
/// <summary>
/// Summary description for Service1
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[ScriptService]
public class Service1 : WebService
{
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string[] GetCitiesWithState(string isoalpha2, string prefixText)
{
return new string[] { "New Orleans, Lousiana", "New York, New York" };
}
}
}

The reason that the asmx webmethod is returning XML rather than JSON is because the HTTP method is GET rather than POST.
In order for the autocomplete plugin to use POST you'll have to implement the source parameter using a callback function, see here

Related

Adding custom header to generated WebService helper

Is the a way to add or customize the headers when using the generated javascript that is created from .asmx files?
For example I have a webservice like:
SomeService.asmx
[WebService(Namespace = "https://www.somedomain.com/api/someapi", Description = "api", Name = "someapi")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class WebService : System.Web.Services.WebService
{
[WebMethod]
[HttpPost]
[ScriptMethod(ResponseFormat=ResponseFormat.Json)]
public List<SomeModel> GetData(string SomeArgument)
{
string customHeaderValue = HttpContext.Current.Request.Headers.Get("SomeCustomHeader");
// Do things
}
}
Now using jQuery I can specify the custom header like:
jQuery.ajax({
type: 'POST',
url: '/Path/ToFile/Webservice.asmx/GetData',
data: "data",
success: OnSuccessFunc,
error: OnFailureFunc,
headers: {
'SomeCustomHeader': "SomeCustomHeaderValue" <---
}
});
But I know that the asmx files can generate some helper functions javascript that will handle everything for me. For example if I add
<script type="text/javascript" src="/Path/ToFile/Webservice.asmx/js"></script>
then on the page i can simply write
<script type="text/javascript">
Webservice.GetData("data", OnSuccessFunc, OnFailureFunc)
</script>
But how would I include the custom header data using the generated javascript version?
You can try to setup a header to every request using beforeSend hook with $.ajaxSetup()
Take a look at this URL.
https://www.edureka.co/community/82342/how-to-add-custom-http-header-to-ajax-request-with-javascript

Convert string to HTML to inject to paragraph via WebMethod

Im doing a Maintenance Page where people can store the description of what it will say in a Resource file, at this point in the requirement they dont even know if the text will be pure text or will have tags like <a></a>. So at this point I have to assume it will be the case.
This proyect have been made in Webforms framework 3.5 in VS2010.
For simplicity sake I'll reveal the relevant parts:
<article>
<img alt="an image" src="Images/logo.jpg"/>
<h2>Site under Maintenance</h2>
<div>
<p id="Description"></p>
</div>
</article>
<script src="Includes/jquery-1.12.3.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$.ajax({
type: "GET",
url: "MaintenanceSite.aspx/GetMaintenanceDescription",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
$("#Description").text(msg.d);
}
});
});
</script>
Backend:
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public static string GetMaintenanceDescription()
{
string mensaje = HttpUtility.HtmlEncode(Resources.MaintenanceDescription);
return mensaje;
}
The problem is, Im receiving this on my paragraph:
<To href="">Contact Us</a>
(without the spaces as stack overflow is parsing the html correctly).
What am I missing?
There's two issues here. Firstly you need to remove the call to HtmlEncode() in the C# logic to return a plain HTML string. Secondly you need to use jQuery's html() method to display it instead of text(), as the latter will again encode the HTML.
string mensaje = Resources.MaintenanceDescription;
$("#Description").html(msg.d);

Is It possible to use web method in C# class?

I'm using web method in C# class file(i.e not a partial class of any web form) and I have html file. I just want to call web method from html file using JQuery AJAX GET and POST methods. Is it possible to do this? Is this have any sense? or i must want use asp web form?
To answer your question it's important that you first understand the prurpose of having a web service.Web services allow us to expose any piece of software over the internet and allow clients to consume it.
In .NET ASMX web services we expose software to the outside world by decorating methods with the [WebMethod] attribute.But even if we apply the [WebMethod] attribute our method will not be available over the internet unless it's inisde a:
.asmx web service file
.aspx web page
Hopefully now you understand why you can't simply define a [WebMethod] inside a standard C# class.Below is a simple example of calling an ASMX web service from a plain html page:
MyService.asmx:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class MyService : System.Web.Services.WebService
{
[WebMethod]
public string GreetUser(string name)
{
return String.Format("Hello {0}",name);
}
}
Index.html:
<html>
<head>
<title></title>
<meta charset="utf-8" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.3/jquery.min.js"></script>
<script type="text/javascript">
$(function () {
$("#btnCallService").click(function () {
$.ajax({
type: "POST",
url: "MyService.asmx/GreetUser",
contentType: "application/json;charset=utf-8",
data: '{name:"' + $("#txtName").val() + '"}',
dataType: "json",
success: function (data) {
alert(data.d);
},
error: function (errordata) {
console.log(errordata);
}
});
});
});
</script>
</head>
<body>
<input type="text" id="txtName" />
<input type="button" value="Call Service" id="btnCallService" />
</body>
</html>
Yes you can. Your html file can include a tag with functions that make ajax calls.
Here is a simple example from W3School's site:
<!DOCTYPE html>
<html>
<body>
<div id="demo"><h2>Let AJAX change this text</h2></div>
<button type="button" onclick="loadDoc()">Change Content</button>
</body>
</html>
You see that the button has an 'onClick' event, which calls the loadDoc function.
And this is the function:
function loadDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 200) {
document.getElementById("demo").innerHTML = xhttp.responseText;
}
};
xhttp.open("GET", "ajax_info.txt", true);
xhttp.send();
}
Here is the link to the tutorial's page:
http://www.w3schools.com/ajax/
Your Ajax Call on HTML will look very similar to this
var options = {
type: "POST",
url: '<%=ResolveUrl("~/FileLocationWhereWebMethodIsDefined") %>',
data: "{'Add Parameters if your web method needs it'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
beforeSend: function () {
//jQuery(".overlay").show();
//jQuery(".progress").show();
},
success: function (msg) {
},
error: function (jqXHR, textStatus, errorThrown) {
// jQuery(".overlay").hide();
// jQuery(".progress").hide();
throw Error; // "error";
}
};
jQuery.ajax(options);

jQuery Ajax call to database on click ASP.net

Let's say I've got a table in a SQL Server database that looks like
StateName notes
alabama 'notes about alabama'
alaska 'notes about alaska'
..... .........
EDIT: This question will be divided into two parts, one for the initial problem and why it didn't work and my reformed, hopefully more accurate second solution.
In the web form, the name of the state are represented as link button inside of a table. I'm trying to use jQuery to make an Ajax database call when a user clicks on a state name, the text value of the link button will be send to a stored procedure in the database.
That stored procedure is something like
create proc spGetStateData
#stateName varchar(50)
as
begin
select notes from
states
where statename = #stateName
end
For testing purposes, I added a a text box and a button so that when the user types the name of the state into the text box, the Notes column from the States database table is displayed.
[WebMethod]
public static string GetStateData(string stateName)
{
string stateNotes = string.Empty;
string cs = ConfigurationManager.ConnectionStrings["dbcs"].ConnectionString;
using (SqlConnection con = new SqlConnection(cs))
{
using (SqlCommand cmd = new SqlCommand("spGetStateData", con))
{
con.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#stateName", stateName);
stateNotes = cmd.ExecuteScalar().ToString();
}
}
return stateNotes;
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
lblStateNotes.Text = GetStateData(txtStateName.Text);
hiddenDiv.Visible = true;
}
This part works, so I know it's not my WebMethod or a database connection that's failing. When I try to do this same thing with jQuery, it fails.
<script type="text/javascript" language="javascript">
$(document).ready(function () {
$("#states a").click(function () {
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "WebForm1.aspx/GetStateData",
data: $(this).text(),
dataType: "json",
success: function (data) {
response(data.d);
},
error: function (x) {
alert('error');
}
});
});
});
</script>
Okay, I pulled open developer tools for Chrome and found out what the reason for the AJAX failing was that I was getting a 'couldn't load resource HTTP 500 error'. It was telling me that the method name and parameter couldn't be found (even though by all rights they were there). So then I tried a second way, which seems like a better way (if I can get it to work!)
So then I thought 'let's use a WebService'. And here is my rendition of that:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$("a").click(function () {
var stateName = JSON.stringify({ "stateName": $(this).text() });
$.ajax({
type: "POST",
url: "GetStateData.asmx/GetData",
contentType: "application/json; charset=utf-8",
data: stateName,
dataType: "json",
success: function (data) {
$("#lblNotes").text(data);
},
error: function (x) {
alert('message');
}
});
});
});
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
Alabama
Alaska
<asp:Label runat="server" ID="lblNotes"></asp:Label>
</div>
</form>
</body>
</html>
web service:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Web.Script.Services;
namespace jQueryAjaxWebservice
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class GetStateData : System.Web.Services.WebService
{
[WebMethod]
[ScriptMethod]
public string GetData(string stateName)
{
string cs = ConfigurationManager.ConnectionStrings["dbcs"].ConnectionString;
string stateNotes ="test" ;
using (SqlConnection con = new SqlConnection(cs))
{
using (SqlCommand cmd = new SqlCommand("spGetStateData",con))
{
con.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#stateName", stateName);
stateNotes = cmd.ExecuteScalar().ToString();
}
}
return stateNotes;
}
}
}
I've tested the WebService, and it works. However, when I try to call the web service code from default.aspx, I get [Object object] as the lblNotes text. If I change (data) to "test" then I get the correct output of "test" to the screen. So the faulty part is in the success portion of the Ajax call. I put a breakpoint on the GetData function and stateNotes is receiving the proper text value, so the only place left for the problem to be is in the success line of the ajax call.
I think the way you format your data option in ajax might be wrong. It always works in key-value pairs. In the current form you are only sending the value, no key. You might have to change it to this format :
var stateName = { "stateName" : $(this).text()}
or
var stateName = JSON.stringify({ "stateName" : $(this).text()})
But mostly, I've seen only the second one to work, partly because jQuery doesn't pre-process the data option for it be readable in C#. So it's always recommended to use stringify on ajax requests with type set to "POST".
Then, in your ajax call,
$.ajax({
//ajax options
data : stateName
//some more ajax options
});
Also, you might want to make your error option more descriptive, like this :
$.ajax({
//ajax options
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
This will tell you where you're going wrong and you could debug it as well.
EDIT:
In the success function, try looking for data.d instead of data. You'll find that your data lies inside it. Also, as mentioned before (and i cant stress this enough), please use error handler with xhr options. It'll be easier to debug then. Read this if you want to know why the result returns data.d and not just data.
$.ajax({
//some ajax options
success: function (data) {
//data.d will contain your data
console.log(data.d);
$("#lblNotes").text(data.d);
},
error: function (xhr, ajaxOptions, thrownError) {
console.log(xhr);
alert(xhr.status);
alert(thrownError);
}
});
Hope this helps!

calling webservice from javascript function and storing the result

This question is with reference to my another question Auto complete not working.
That problem is still there in my code but I thought of doing this other way. I am thinking of calling my webservice from another javascript function and pass the value returned from the service to this autocomplete function as when I try to pass some dummy values to this jquery function its running fine. i am not sure y its is not calling my webservice.
Though now i have written another function to call my service and get the request -
function SendRequest()
{
debugger;
SearchIssues.GetServerResponse(document.getElementById('ctl00_ContentPlaceHolder1_txtIssueNo').value, OnComplete, OnError, OnTimeOut);
}
function OnComplete(arg)
{
alert(arg);
}
function OnTimeOut(arg)
{
alert("timeOut has occured");
}
function OnError(arg)
{
alert("error has occured: " + arg._message);
}
In the script manager tage I have added the reference of my webservice -
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="~/SearchIssues.asmx" />
</Services>
</asp:ScriptManager>
I have updated my autocomplete function as -
$(function() {
debugger;
$(".tb").autocomplete({
source: ["c++", "java", "php", "coldfusion", "javascript", "asp", "ruby"] });});
Here I have passed dummy data in source which is working fine.
the signature of my webservice is as -
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public List<string> GetCompletionList(string prefixText)
{....
}
But its still not calling my webservice and is returning some javascript error as -
SearchIssues is undefined
Please Help
Thanks
this worked for me
[WebMethod]
public static Array GetCompletionList(string code)
{
.....your code
}
$.ajax({
type: "POST",
url: "CompletionList.aspx/GetCompletionList",
data: '{"code1":"' +code1 + '"}',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (c2) {
....your code
});
});
1> I think while calling you should have full namespace
NameSpace.SearchIssues.GetServerResponse(document.getElementById('ctl00_ContentPlaceHolder1_txtIssueNo').value, OnComplete, OnError, OnTimeOut)
2> Your service class must have [ScriptService] attribute.
3> Test your relative URL for the service
"~/SearchIssues.asmx"

Categories