Iterate through JSON object list provided by ASP.NET webservice - asp.net

I have an ASP.NET webservice method that returns a generics list (List'<'Construct>) serialized as JSON, using code such as this:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class TestService : System.Web.Services.WebService {
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string GetOccupationListJSON(int SOCLevel)
{
Construct NewConstructList = new ConstructList();
DataContractJsonSerializer serializer = new DataContractJsonSerializer(ConstructList.GetType());
MemoryStream ms = new MemoryStream();
serializer.WriteObject(ms, NewConstructList);
string json = Encoding.Default.GetString(ms.ToArray());
return json;
}
}
I then use jQuery to call this method, and get the JSON data, like so:
function GetCustomerList() {
$.ajax({
type: "POST",
url: "/WebService.asmx/GetConstructList",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) { LoadConstructData(data.d); },
failure: function() { alert("Sorry, we were unable to find the constructs."); }
});
}
The JSON result looks like this:
[
{
"ConstructLabel": "Construct label 1",
"ConstructType": 2,
},
{
"ConstructLabel": "Construct label 2",
"ConstructType": 3,
}
]
I then want to iterate through the elements in the ConstructList in the JSON data. This is the function that gets called on when the jQuery Ajax call is successful:
function LoadConstructData(data) {
for (var i = 0, len = data.length; i < len; ++i) {
var Construct = data[i];
var ConstructLabel = Construct.ConstructLabel
var ConstructType = Construct.ConstructType;
}
}
I assumed (from looking elsewhere) that accessing the JSON data through the index would provide me with access to the underlying object at that index, so that I can then work with it to access its properties.
However, when i=0 and I do var Construct = data[i]; I get the character at the i position of the data array ([), and in the next iteration I get the second character ({). So clearly I am accessing the elements of a string array rather than the JSON data object.
How do I make sure that the data returned by the webservice gets into proper JSON format, so that I can iterate through the object elements within it?

You shouldn't manually serialize the JSON. The ScriptService will do that for you automatically if you define it like this:
[WebMethod]
public List<Construct> GetConstructList()
{
return new ConstructList();
}

Related

Manipulating the received Json Data in Web API Controller

I am passing Json Data from Angular JS Controller. The Json Data contains two strings called name attribute and comment attribute and a list of files. The controller code for angular is given below:
app.controller("demoController", function ($scope, $http) {
//1. Used to list all selected files
$scope.files = [];
//2. a simple model that want to pass to Web API along with selected files
$scope.jsonData = {
name: "Sibnz",
comments: "This is a comment"
};
//3. listen for the file selected event which is raised from directive
$scope.$on("seletedFile", function (event, args) {
$scope.$apply(function () {
//add the file object to the scope's files collection
$scope.files.push(args.file);
});
});
//4. Post data and selected files.
$scope.save = function () {
$http({
method: 'POST',
url: "http://localhost:51739/PostFileWithData",
headers: { 'Content-Type': undefined },
transformRequest: function (data) {
var formData = new FormData();
formData.append("model", angular.toJson(data.model));
for (var i = 0; i < data.files.length; i++) {
formData.append("file" + i, data.files[i]);
}
return formData;
},
data: { model: $scope.jsonData, files: $scope.files }
}).
success(function (data, status, headers, config) {
alert("success!");
}).
error(function (data, status, headers, config) {
alert("failed!");
});
};
});
In the Web API, controller I am receiving the JSON data by using the following code:
[HttpPost]
[Route("PostFileWithData")]
public async Task<HttpResponseMessage> Post()
{
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var root = HttpContext.Current.Server.MapPath("~/App_Data/Uploadfiles");
Directory.CreateDirectory(root);
var provider = new MultipartFormDataStreamProvider(root);
var result = await Request.Content.ReadAsMultipartAsync(provider);
var model = result.FormData["jsonData"];
var g = result.FileData;
if (model == null)
{
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
//TODO: Do something with the JSON data.
//get the posted files
foreach (var file in result.FileData)
{
//TODO: Do something with uploaded file.
var f = file;
}
return Request.CreateResponse(HttpStatusCode.OK, "success!");
}
When I debug the code, I find that the JSON data is populating the var model and var g variables. I want to extract the name and comment attributes from the Json Data and store them in the Database. And also want to copy the file into /App_Data/Uploadfiles directory and store the file location in the database.
You need to create a model in your Web API and deserialize JSON data to this model, you can use Newtonsoft.Json NuGet package for that
Install-Package Newtonsoft.Json
class DataModel
{
public string name { get; set; }
public string comments { get; set; }
}
In Web API controller
using Newtonsoft.Json;
HttpRequest request = HttpContext.Current.Request;
var model = JsonConvert.DeserializeObject<DataModel>(request.Form["jsonData"]);
// work with JSON data
model.name
model.comments
To work with files
// Get the posted files
if (request.Files.Count > 0)
{
for (int i = 0; i < request.Files.Count; i++)
{
Stream fileStream = request.Files[i].InputStream;
Byte[] fileBytes = new Byte[stampStream.Length];
// Do something with uploaded file
var root = HttpContext.Current.Server.MapPath("~/App_Data/Uploadfiles/");
string fileName = "image.jpg";
File.WriteAllBytes(root + fileName, stampBytes);
// Save only file name to your database
}
}

Kendo Grid Server side paging in ASP.Net WebForms gives error: Cannot read property 'slice' of undefined

I am trying to integrate server side paging in Telerik Kendo Grid in my ASP.Net WebForms Application. I am using web service for getting data from database. I have integrate everything as documented on Telerik website. But Grid is not populating the data. It gives javascript error in console like :
Uncaught TypeError: Cannot read property 'slice' of undefined ............... kendo.all.min.js:27
Here is what I have used so far:
In ASPX Page:
<script type="text/javascript">
$(document).ready(function () {
$("#grid").kendoGrid({
dataSource: {
transport: {
read: "/AjaxPages/KendoGrid.asmx/GetUserListPageWise",
dataType: "json",
contentType: "application/json;charset=utf-8"
},
schema: {
data: "data", // records are returned in the "data" field of the response
total: "total"
},
pageSize: 10,
serverPaging: true,
//serverFiltering: true,
},
height: 430,
filterable: true,
sortable: true,
pageable: true,
columns: [
{
field: "Id",
title: "Id",
filterable: true
},
{
field: "FirstName",
title: "Name",
filterable: true
}
]
});
});
</script>
In Code Behind Page (Web Service) :
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json, UseHttpGet = true)]
public string GetUserListPageWise(int take, int skip, int page, int pageSize)
{
JavaScriptSerializer js = new JavaScriptSerializer();
Context.Response.Clear();
Context.Response.ContentType = "application/json";
int companyid = Convert.ToInt32(HttpContext.Current.Session["CompanyId"]);
List<UserList> lst = new List<UserList>();
UserMaster user = new UserMaster();
lst = user.GetPagingGridList(skip, pageSize, companyid);
//KendoResponse d = new KendoResponse { results = lst, __count = lst.Count };
//return lst;
var result = new KendoResponse(lst.ToArray(), lst.Count);
//return result;
return new JavaScriptSerializer().Serialize(result);
//return new JavaScriptSerializer().Serialize(new { total = lst.Count, data = lst });
}
And here is the model class used :
public class KendoResponse
{
public Array data { get; set; }
public int total { get; set; }
public KendoResponse(Array _data, int _total)
{
this.data = _data;
this.total = _total;
}
}
I am getting response of ajax call made by Kendo Grid, the response is like :
<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://mywebsite.net/">{"data":[{"Id":9,"FirstName":"Sachin","LastName":"Patel","EmailId":"admin#a.com","Password":null,"MobileNo":"","CompanyName":"Company","RoleName":"Admin","ModifiedOn":"\/Date(1465465583063)\/"},{"Id":8,"FirstName":"Abc","LastName":"Xyz","EmailId":"user#user.com","Password":null,"MobileNo":"","CompanyName":"Company2","RoleName":"User","ModifiedOn":"\/Date(1465277042557)\/"},{"Id":2,"FirstName":"Aaabb","LastName":"Xxxyy","EmailId":"a#a.com","Password":null,"MobileNo":"","CompanyName":"Company2","RoleName":"Admin","ModifiedOn":"\/Date(1463737813523)\/"}],"total":3}</string>
But still its not binding data to Grid. It is giving an error in Kendo js file.
Can any one help me?
Thanks in advance..
Finally I found solution after stretching my hairs for 2 days:
Grid was not binding as I am not getting json response from my web service. It is giving me json object as a string in xml format due to which the grid is not binding. I have resolved the issue by simply sending json response in HTTPContext by following way: (thanks to Saranya, I have read this SO answer)
[WebMethod(EnableSession = true)]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public void GetUserListPageWise(int take, int skip, int page, int pageSize)
{
JavaScriptSerializer js = new JavaScriptSerializer();
Context.Response.Clear();
Context.Response.ContentType = "application/json";
int companyid = Convert.ToInt32(HttpContext.Current.Session["CompanyId"]);
List<UserList> lst = new List<UserList>();
UserMaster user = new UserMaster();
lst = user.GetPagingGridList(skip, pageSize, companyid);
int lstCount = user.GetPagingGridListCount(companyid);
var result = new KendoResponse(lst.ToArray(), lst.Count);
//Context.Response.Write(result);
Context.Response.Write(new JavaScriptSerializer().Serialize(new KendoResponse(lst.ToArray(), lstCount)));
//return new JavaScriptSerializer().Serialize(result);
}

stop old session list object to add up

what my code 'below' does is: the client javascript calls a webservice method which creates a generic list and then stores it into a session.
[WebMethod(EnableSession = true)]
public void SaveUserSelection(string slctdRooms, string slctdcst)
{
List<SelectRms> SelectR = Session["someinfo"] as List<SelectRms>;
if (SelectR == null)
{
SelectR = new List<SelectRms>();
Session["someinfo"] = SelectR;
}
SelectR.Add(new SelectRms { roomtype = slctdRooms, Roomcst = slctdcst });
}
I would then retreave the session to show the data in another page like this
List(SlctdRmWebSrv.SelectRms) SelctdRM = (List(SlctdRmWebSrv.SelectRms))Sessio["someinfo"];
if(SelctdRM != null)
{
repeater1.DataSource = SelctdRM;
repeater1.DataBind();
}
the problem is that every time I retreave the session to create a new list, the new data is added up to the old one. I want to have a situation where only the current data is displayed. I tried to clear the list, abandon the session, or clear the repeater before adding the new ones it did hehlp; easy there an easy way to get this done. many thanks
It sounds like you are calling SaveUserSelection multiple times from your javascript. If that's the case then only the very first time your list will be initialized.
Therefore, your list will keep adding stuff to the "old" list since the list has not been cleared or re-initialized .
You should probably put the initialization in a separate method (either on Page_Load or create a new WebMethod just to clear/initialized the list). For example, this is how it looks if you decide to put it on the Page_Load event:
Note: code no tested
private void Page_Load(object sender, System.EventArgs e)
{
if(!Page.IsPostBack)
Session["someinfo"] = new List<SelectRms>();
}
This is how it looks if you create a WebMethod:
[WebMethod(EnableSession = true)]
public void InitUserSelection()
{
Session["someinfo"] = new List<SelectRms>();
}
Call this method when you are ready to keep track of the user selection. Perhaps when your form initially loads (place this script at the bottom of the page):
$(document).ready(function() {
$.ajax({
type: "POST",
url: "PageName.aspx/InitUserSelection",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
// After init you could use this method to do something else
}
});
});
So SaveUserSelection will look like this:
[WebMethod(EnableSession = true)]
public void SaveUserSelection(string slctdRooms, string slctdcst)
{
List<SelectRms> SelectR = Session["someinfo"] as List<SelectRms>;
if (SelectR != null)
SelectR.Add(new SelectRms { roomtype = slctdRooms, Roomcst = slctdcst });
}
And this is how your javascript looks like whenever your selection changes:
$.ajax({
type: "POST",
url: "PageName.aspx/SaveUserSelection",
data: "{'slctdRooms':'Value1','slctdcst':'Value2'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
//your list was updated, you may do something afterwards
}
});
#Ulises. this is what I ma doing:
public List<SelectRms> GetUserContent()
{
List<SelectRms> SelectR=new List<SelectRms>();
Session["someinfo"] = SelectR;
return Session["someinfo"] as List<SelectRms>;
}
[WebMethod(EnableSession = true)]
public void SaveUserSelection(string slctdRooms, string slctdcst)
{
List<SelectRms> SelectR = GetUserContent();
SelectR.Add(new SelectRms { roomtype = slctdRooms, Roomcst = slctdcst });
}
But instead it returns a single (first) element of my list rather than the whole list, Any Help

selecting all the records from the database using jquery ajax in asp.net

i want to generate the table of contents from database.. using jquery ajax in asp.net, i am using sql server 2008 as a backend. for this i created a webmethod in my normal aspx page. and on the clientside wrote the ajax script to fetch records but when i loop through the results, i gets message undefined and nothing happens.. i want to generate table out of the records from database below is my webmethod.
[WebMethod]
public static Poll[] GetPollDetailed()
{
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["SiteSqlServer"].ConnectionString);
SqlDataAdapter da = new SqlDataAdapter("sp_SelectQuestion", con);
da.SelectCommand.CommandType = CommandType.StoredProcedure;
da.SelectCommand.Parameters.AddWithValue("#siteid", 3);
DataTable dt = new DataTable();
da.Fill(dt);
List<Poll> _poll1 = new List<Poll>();
foreach (DataRow row in dt.Rows)
{
Poll _poll = new Poll();
_poll.QuestionID = Convert.ToInt32(row["questionID"]);
_poll.Question = row["question"].ToString();
_poll.Published = Convert.ToInt32(row["visible"]);
_poll.Date = Convert.ToDateTime(row["Added_Date"]);
}
return _poll1.ToArray();
}
public class Poll
{
public Poll() { }
private int _questionId, _published;
private string _question;
private DateTime _date;
public int QuestionID
{
get { return _questionId; }
set { _questionId = value; }
}
public string Question
{
get { return _question; }
set { _question = value; }
}
public DateTime Date
{
get { return _date; }
set { _date = value; }
}
public int Published
{
get { return _published; }
set { _published = value; }
}
}
</code>
and below is my script.
<code>
$(this).load(function () {
$.ajax({
type: "POST",
url: "AddPollAJax.aspx/GetPollDetailed",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
for (i = 0; i < data.length; i++) {
alert(data[i].QuestionID);
}
},
error: function (data) {
alert("Error: " + data.responseText);
}
});
});
</code>
can any one please help me to resolve this issue, i am very curious about it.
Assuming your service is configured correctly to return JSON data, issue lies at your js code fragment for success callback i.e.
success: function (data) {
for (i = 0; i < data.length; i++) {
alert(data[i].QuestionID);
}
},
MS ASP.NET script services always return a wrapped JSON due to security issues, so you need unwrap resultant JS object to get the actual data. So you need to change the code to
success: function (result) {
var data = result.d; // actual response will be in this property
for (i = 0; i < data.length; i++) {
alert(data[i].QuestionID);
}
},
BTW, ASP.NET Web Services are now considered legacy, so I will suggest you to migrate to WCF services instead.

Model Binding a json array containing different object types in Asp.Net MVC

I have a json array containing integers and objects.
[1,2,3,{Name:"russia",Value:6},{Name:"usa",Value:"8"}]
I also have the following server-side class
class country {
string Name;
int Value;
}
How should I go about binding the json array to a server-side parameter ? I tried using a List<object> on server. It binds the integers fine but no country instances are created. Instead, primitive objects are created and added to the list.
Thanks.
You could try something like this:
Format your controller action to accept a List<int> for your integer values and a List<Country> for your Country objects.
public ActionResult Index(List<int> intValues, List<Country> countryValues)
Then build your JSON like so that it contains and array of integers and an array of country objects:
var postData = {
intValues: [1, 2, 3],
countryValues: [
{ Name: 'USA', Value: 6 },
{ Name: 'Russia', Value: 8 }
]
};
And perform a simple AJAX call to send the data
$(function() {
$.ajax({
type: 'POST',
url: "#Url.Action("Create")",
contentType: "application/json",
data: JSON.stringify(postData)
});
});
Okay, I solved it at last. I created a custom model binder derived from the default model binder to accomplish this. Here's the code.
public ActionResult Home(NonHomogeneousList input)
[ModelBinder(typeof(CustomModelBinder))]
class NonHomogeneousList : List<object>
public class CustomModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
NonHomogeneousList model = (NonHomogeneousList)base.BindModel(controllerContext, bindingContext);
if (model.Members != null)
{
IModelBinder countryBinder = Binders.GetBinder(typeof(Country));
// find out if the value provider has the required prefix
bool hasPrefix = bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName);
string prefix = (hasPrefix) ? bindingContext.ModelName + "." : "";
for (var i = 0; i < model.Count; i++)
{
var member = model.Members[i];
if (member.GetType().Equals(typeof(object)))
{
var subKey = CreateSubIndexName( prefix , i);
ModelBindingContext innerContext = new ModelBindingContext()
{
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(Country)),
ModelName = subKey,
ModelState = bindingContext.ModelState,
PropertyFilter = bindingContext.PropertyFilter,
ValueProvider = bindingContext.ValueProvider,
};
var country = countryBinder.BindModel(controllerContext, innerContext);
model.Members[i] = country;
}
}
}
return model;
}
}
}

Resources