How to implement multiple searching in jqGrid - asp.net
I have a jqGrid which I am using with asp.Net Web Forms , it shows the required information properly from the database , however it shows the search option as well but if I try to search lets say First Name that is Equal to Lijo , it just does not show up that record.The record exists.I know I am missing some stuff required for searching surely , here is the code
<script type="text/javascript">
$(function() {
$("#UsersGrid").jqGrid({
url: 'ModCust.ashx',
datatype: 'json',
height: 250,
width: 800,
colNames: ['Application No', 'First Name', 'Middle Name', 'Last Name'],
colModel: [
{ name: 'cApplicationNo', index: 'cApplicationNo', width: 100, sortable: true},
{ name: 'cFirstName', width: 100, sortable: true},
{ name: 'cMiddleName', width: 100, sortable: true },
{ name: 'cLastName', width: 100, sortable: true },
],
cmTemplate: { title: false},
rowNum: 10,
rowList: [10, 20, 30],
pager: '#UsersGridPager',
sortname: 'cApplicationNo',
viewrecords: true,
sortorder: 'asc',
caption: 'Customer Details'
});
$("#UsersGrid").jqGrid('navGrid', '#UsersGridPager', { edit: false, add: false, del: false });
});
</script>
Here is my ModCust.ashx handler
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Data.SqlClient;
using System.Web;
using System.Web.Script.Serialization;
namespace CwizBankApp
{
public struct JQGridResults
{
public int page;
public int total;
public int records;
public JQGridRow[] rows;
}
public struct JQGridRow
{
public string id;
public string[] cell;
}
[Serializable]
public class User
{
public string ApplicationNo { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
}
/// <summary>
/// Summary description for $codebehindclassname$
/// </summary>
public class ModCust : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
HttpRequest request = context.Request;
HttpResponse response = context.Response;
string _search = request["_search"];
string numberOfRows = request["rows"];
string pageIndex = request["page"];
string sortColumnName = request["sidx"];
string sortOrderBy = request["sord"];
int totalRecords;
//Collection<User> users = GetDummyUsers(numberOfRows, pageIndex, sortColumnName, sortOrderBy, out totalRecords);
Collection<User> users = GetUsers(numberOfRows, pageIndex, sortColumnName, sortOrderBy, out totalRecords);
string output = BuildJQGridResults(users, Convert.ToInt32(numberOfRows), Convert.ToInt32(pageIndex), Convert.ToInt32(totalRecords));
response.Write(output);
}
private string BuildJQGridResults(Collection<User> users, int numberOfRows, int pageIndex, int totalRecords)
{
JQGridResults result = new JQGridResults();
List<JQGridRow> rows = new List<JQGridRow>();
foreach (User user in users)
{
JQGridRow row = new JQGridRow();
row.id = user.ApplicationNo;
row.cell = new string[4];
row.cell[0] = user.ApplicationNo;
row.cell[1] = user.FirstName;
row.cell[2] = user.MiddleName;
row.cell[3] = user.LastName;
rows.Add(row);
}
result.rows = rows.ToArray();
result.page = pageIndex;
result.total = (totalRecords + numberOfRows - 1) / numberOfRows;
result.records = totalRecords;
return new JavaScriptSerializer().Serialize(result);
}
private Collection<User> GetDummyUsers(string numberOfRows, string pageIndex, string sortColumnName, string sortOrderBy, out int totalRecords)
{
var data = new Collection<User> {
new User(){ FirstName = "Bill", LastName = "Gates", ApplicationNo= "1", MiddleName = "Bill Gates"}
};
totalRecords = data.Count;
return data;
}
private Collection<User> GetUsers(string numberOfRows, string pageIndex, string sortColumnName, string sortOrderBy, out int totalRecords)
{
Collection<User> users = new Collection<User>();
string connectionString = "Server=Server;Database=CwizData;Trusted_Connection=True";
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand())
{
command.Connection = connection;
command.CommandText = "select cApplicationNo,cFirstName,cMiddleName,cLastName from Data_Customer_Log";
command.CommandType = CommandType.Text; // StoredProcedure;
SqlParameter paramPageIndex = new SqlParameter("#PageIndex", SqlDbType.Int);
paramPageIndex.Value = Convert.ToInt32(pageIndex);
command.Parameters.Add(paramPageIndex);
SqlParameter paramColumnName = new SqlParameter("#SortColumnName", SqlDbType.VarChar, 50);
paramColumnName.Value = sortColumnName;
command.Parameters.Add(paramColumnName);
SqlParameter paramSortorderBy = new SqlParameter("#SortOrderBy", SqlDbType.VarChar, 4);
paramSortorderBy.Value = sortOrderBy;
command.Parameters.Add(paramSortorderBy);
SqlParameter paramNumberOfRows = new SqlParameter("#NumberOfRows", SqlDbType.Int);
paramNumberOfRows.Value = Convert.ToInt32(numberOfRows);
command.Parameters.Add(paramNumberOfRows);
SqlParameter paramTotalRecords = new SqlParameter("#TotalRecords", SqlDbType.Int);
totalRecords = 0;
paramTotalRecords.Value = totalRecords;
paramTotalRecords.Direction = ParameterDirection.Output;
command.Parameters.Add(paramTotalRecords);
connection.Open();
using (SqlDataReader dataReader = command.ExecuteReader())
{
User user;
while (dataReader.Read())
{
user = new User();
user.ApplicationNo =Convert.ToString(dataReader["cApplicationNo"]);
user.FirstName = Convert.ToString(dataReader["cFirstName"]);
user.MiddleName = Convert.ToString(dataReader["cMiddleName"]);
user.LastName = Convert.ToString(dataReader["cLastName"]);
users.Add(user);
}
}
//totalRecords =(int)(paramTotalRecords.Value);
// totalRecords = 0;
}
return users;
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
Can someone help me out with this,
Any suggestions are welcome , thanks
In your question you used mostly the demo project from my old answer. All other later answers which shows how to implement Advanced Searching, paging and sorting on the server (for example this one or this one) I used more recent ASP.NET technologies, mostly ASP.NET MVC. On the other side the code from the demos one can decide in following parts:
The server code which provide some interface which can be used by jqGrid to get JSON response. It can be ASP.NET MVC controller action, WFC method, WebMethod of ASMX web service or General ASHX Handler like you use.
The server code which analyse the input parameter send by jqGrid. The default names of the parameters are page, rows, sidx, sord, _search, filters. One can rename the parameters using prmNames option of jqGrid.
Access to the database. The part of the server code depends on the technology which you use. It can be for example Entity Framework, LINQ to SQL or more old but with good performance SqlCommand with SqlDataReader.
Encoding of results as JSON. One can use for example standard JavaScriptSerializer or DataContractJsonSerializer or high-performance JSON framework Json.NET (knows as Newtonsoft.JSON). Microsoft uses and supports the open source Json.NET serializer in the new version of ASP.NET MVC 4.0 and ASP.NET Web API. One can include Json.NET in the ASP.NET project and can update it to the last recent version using NuGet.
Handling on the server the exceptions and reporting the error information to the clients (jqGrid) in the JSON format. The code is a little different depend on the technology used on the server. The client code in loadError callback of jqGrid should decode the error information and display it in some form. In case of usage ASP.NET MVC I shown in the answer how to implement HandleJsonExceptionAttribute attribute which can be used as [HandleJsonException] instead of the standard [HandleError]. In case of usage WCF one can use WebFaultException<string> (see here). In case of General ASHX Handler one can use Application_Error of Global.asax for the purpose.
Optionally one can includes in the server code setting of ETag in the HTTP header. It allows to control client side cache on the server side. If the client need JSON data previously returned from the server it will automatically send If-None-Match part in the HTTP request to the server which contain ETag from the previous server response. The server can verify whether the server data are changed since the last response. At the end the server will either returns the new JSON data or an empty response which allows the client to use the data from the old response.
One need to write JavaScript code which create jqGrid.
I made the demo project which demonstrate all the above steps. It contains small Database which I fill with information about some from the famous mathematicians. The demo display the grid
where one can use sorting, paging, toolbar filtering or advanced searching. In case of some error (for example if you stop Windows Service "SQL Server (SQLEXPRESS)") you will see the error message like the following:
The C# code which implements ASHX handle in the demo is
using System;
using System.Globalization;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using Newtonsoft.Json;
namespace jqGridASHX {
// ReSharper disable InconsistentNaming
public class jqGridData : IHttpHandler {
// ReSharper restore InconsistentNaming
public void ProcessRequest (HttpContext context) {
// to be able to use context.Response.Cache.SetETag later we need the following:
context.Response.Cache.SetCacheability(HttpCacheability.ServerAndPrivate);
// to use with HTTP GET we want be sure that caching of data work correct
// so we request revalidation of data by setting in HTTP header the line
// "Cache-Control: private, max-age=0"
context.Response.Cache.SetMaxAge (new TimeSpan (0));
string numberOfRows = context.Request["rowsPerPage"];
int nRows, iPage;
if (String.IsNullOrEmpty (numberOfRows) || !int.TryParse (numberOfRows, NumberStyles.Integer, CultureInfo.InvariantCulture, out nRows))
nRows = 10; // default value
string pageIndex = context.Request["pageIndex"];
if (String.IsNullOrEmpty(pageIndex) || !int.TryParse(pageIndex, NumberStyles.Integer, CultureInfo.InvariantCulture, out iPage))
iPage = 10; // default value
string sortColumnName = context.Request["sortByColumn"];
string sortOrder = context.Request["sortOrder"];
string search = context.Request["isSearching"];
string filters = context.Request["filters"];
// we can use high-performance Newtonsoft.Json
string str = JsonConvert.SerializeObject (
MyData.GetDataForJqGrid (
nRows, iPage, sortColumnName,
!String.IsNullOrEmpty (sortOrder) &&
String.Compare (sortOrder, "desc", StringComparison.Ordinal) == 0
? MyData.SortOrder.Desc
: MyData.SortOrder.Asc,
search != null && String.Compare (search, "true", StringComparison.Ordinal) == 0,
filters));
context.Response.ContentType = "application/json";
// calculate MD5 from the returned data and use it as ETag
byte[] hash = MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(str));
string newETag = Convert.ToBase64String(hash);
// compare ETag of the data which already has the client with ETag of response
string incomingEtag = context.Request.Headers["If-None-Match"];
if (String.Compare(incomingEtag, newETag, StringComparison.Ordinal) == 0)
{
// we don't need return the data which the client already have
context.Response.SuppressContent = true;
context.Response.StatusCode = (int)HttpStatusCode.NotModified;
return;
}
context.Response.Cache.SetETag(newETag);
context.Response.Write(str);
}
public bool IsReusable {
get { return false; }
}
}
}
It uses Newtonsoft.Json for JSON serialization and uses MD5 hash as ETag.
The method MyData.GetDataForJqGrid provide the data from the database. In the demo I use mainly the code from the answer, so I use Entity Framework to access the database:
using System;
using System.Data.Objects;
using System.Globalization;
using System.Linq;
using Newtonsoft.Json;
namespace jqGridASHX
{
public static class MyData
{
public enum SortOrder {
Asc,
Desc
}
public static Object GetDataForJqGrid(int nRows, int iPage,
string sortColumnName, SortOrder sortOrder,
bool isSearch, string filters)
{
var context = new MyDatabaseEntities();
var f = (!isSearch || string.IsNullOrEmpty(filters)) ? null : JsonConvert.DeserializeObject<Filters>(filters);
ObjectQuery<User> filteredQuery =
f == null ? context.Users : f.FilterObjectSet(context.Users);
filteredQuery.MergeOption = MergeOption.NoTracking; // we don't want to update the data
var totalRecords = filteredQuery.Count();
var pagedQuery =
filteredQuery.Skip(
"it." + (String.IsNullOrEmpty(sortColumnName) ? "Id" : sortColumnName) + " " + sortOrder,
"#skip",
new ObjectParameter("skip", (iPage - 1) * nRows))
.Top("#limit", new ObjectParameter("limit", nRows));
// to be able to use ToString() below which is NOT exist in the LINQ to Entity
// we should include in queryDetails only the properies which we will use below
var queryDetails = (from item in pagedQuery
select new {
item.Id, item.FirstName, item.LastName, item.Birthday
}).ToArray();
return new {
total = (totalRecords + nRows - 1) / nRows,
page = iPage,
records = totalRecords,
rows = (from item in queryDetails
select new[] {
// In the demo we send Id as the 4-th element of row array.
// The value will be not displayed in the grid, but used as rowid
// (the id attribute of the <tr> in the <table>)
item.FirstName,
item.LastName,
item.Birthday == null? String.Empty : ((DateTime)item.Birthday).ToString("yyyy-MM-dd"),
item.Id.ToString (CultureInfo.InvariantCulture)
}).ToArray()
};
}
}
}
where the class Filters
using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Text;
namespace jqGridASHX
{
public class Filters
{
// ReSharper disable InconsistentNaming
public enum GroupOp
{
AND,
OR
}
public enum Operations
{
eq, // "equal"
ne, // "not equal"
lt, // "less"
le, // "less or equal"
gt, // "greater"
ge, // "greater or equal"
bw, // "begins with"
bn, // "does not begin with"
//in, // "in"
//ni, // "not in"
ew, // "ends with"
en, // "does not end with"
cn, // "contains"
nc // "does not contain"
}
public class Rule
{
public string field { get; set; }
public Operations op { get; set; }
public string data { get; set; }
}
public GroupOp groupOp { get; set; }
public List<Rule> rules { get; set; }
// ReSharper restore InconsistentNaming
private static readonly string[] FormatMapping = {
"(it.{0} = #p{1})", // "eq" - equal
"(it.{0} <> #p{1})", // "ne" - not equal
"(it.{0} < #p{1})", // "lt" - less than
"(it.{0} <= #p{1})", // "le" - less than or equal to
"(it.{0} > #p{1})", // "gt" - greater than
"(it.{0} >= #p{1})", // "ge" - greater than or equal to
"(it.{0} LIKE (#p{1}+'%'))", // "bw" - begins with
"(it.{0} NOT LIKE (#p{1}+'%'))", // "bn" - does not begin with
"(it.{0} LIKE ('%'+#p{1}))", // "ew" - ends with
"(it.{0} NOT LIKE ('%'+#p{1}))", // "en" - does not end with
"(it.{0} LIKE ('%'+#p{1}+'%'))", // "cn" - contains
"(it.{0} NOT LIKE ('%'+#p{1}+'%'))" //" nc" - does not contain
};
internal ObjectQuery<T> FilterObjectSet<T>(ObjectQuery<T> inputQuery) where T : class
{
if (rules.Count <= 0)
return inputQuery;
var sb = new StringBuilder();
var objParams = new List<ObjectParameter>(rules.Count);
foreach (var rule in rules)
{
var propertyInfo = typeof(T).GetProperty(rule.field);
if (propertyInfo == null)
continue; // skip wrong entries
if (sb.Length != 0)
sb.Append(groupOp);
var iParam = objParams.Count;
sb.AppendFormat(FormatMapping[(int)rule.op], rule.field, iParam);
ObjectParameter param;
switch (propertyInfo.PropertyType.FullName)
{
case "System.Int32": // int
param = new ObjectParameter("p" + iParam, Int32.Parse(rule.data));
break;
case "System.Int64": // bigint
param = new ObjectParameter("p" + iParam, Int64.Parse(rule.data));
break;
case "System.Int16": // smallint
param = new ObjectParameter("p" + iParam, Int16.Parse(rule.data));
break;
case "System.SByte": // tinyint
param = new ObjectParameter("p" + iParam, SByte.Parse(rule.data));
break;
case "System.Single": // Edm.Single, in SQL: float
param = new ObjectParameter("p" + iParam, Single.Parse(rule.data));
break;
case "System.Double": // float(53), double precision
param = new ObjectParameter("p" + iParam, Double.Parse(rule.data));
break;
case "System.Boolean": // Edm.Boolean, in SQL: bit
param = new ObjectParameter("p" + iParam,
String.Compare(rule.data, "1", StringComparison.Ordinal) == 0 ||
String.Compare(rule.data, "yes", StringComparison.OrdinalIgnoreCase) == 0 ||
String.Compare(rule.data, "true", StringComparison.OrdinalIgnoreCase) == 0);
break;
default:
// TODO: Extend to other data types
// binary, date, datetimeoffset,
// decimal, numeric,
// money, smallmoney
// and so on.
// Below in the example for DateTime and the nullable DateTime
if (String.Compare(propertyInfo.PropertyType.FullName, typeof(DateTime?).FullName, StringComparison.Ordinal) == 0 ||
String.Compare(propertyInfo.PropertyType.FullName, typeof(DateTime).FullName, StringComparison.Ordinal) == 0)
{
// we use below en-US locale directly
param = new ObjectParameter("p" + iParam, DateTime.Parse(rule.data, new CultureInfo("en-US"), DateTimeStyles.None));
}
else {
param = new ObjectParameter("p" + iParam, rule.data);
}
break;
}
objParams.Add(param);
}
var filteredQuery = inputQuery.Where(sb.ToString());
foreach (var objParam in objParams)
filteredQuery.Parameters.Add(objParam);
return filteredQuery;
}
}
}
The code from Global.asax.cs is
using System;
using System.Collections.Generic;
using System.Net;
using System.Reflection;
using System.Web;
using Newtonsoft.Json;
namespace jqGridASHX
{
internal class ExceptionInformation
{
public string Message { get; set; }
public string Source { get; set; }
public string StackTrace { get; set; }
public string ErrorCode { get; set; }
}
public class Global : HttpApplication
{
protected void Application_Error(object sender, EventArgs e)
{
if (Request.ContentType.Contains("application/json"))
{
Response.Clear();
Response.StatusCode = (int)HttpStatusCode.InternalServerError;
Response.Cache.SetMaxAge(new TimeSpan(0));
Response.ContentType = "application/json";
var exInfo = new List<ExceptionInformation>();
for (var ex = Server.GetLastError(); ex != null; ex = ex.InnerException) {
PropertyInfo propertyInfo = ex.GetType().GetProperty ("HResult");
exInfo.Add (new ExceptionInformation {
Message = ex.Message,
Source = ex.Source,
StackTrace = ex.StackTrace,
ErrorCode = propertyInfo != null && propertyInfo.GetValue (ex, null) is int
? "0x" + ((int)propertyInfo.GetValue (ex, null)).ToString("X")
: String.Empty
});
}
Response.Write(JsonConvert.SerializeObject(exInfo));
Context.Server.ClearError();
}
}
}
}
On the client side I used pure HTML page to show mostly clear that you can include the solution in any your project inclusive Web Form project. The page has the following code
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>https://stackoverflow.com/q/10698254/315935</title>
<meta charset="UTF-8" />
<link rel="stylesheet" href="Content/themes/redmond/jquery-ui.css" />
<link rel="stylesheet" href="Scripts/jqGrid/4.3.3/ui.jqgrid.css" />
<link rel="stylesheet" href="Content/Site.css" />
<script src="Scripts/jquery-1.7.2.min.js" type="text/javascript"></script>
<script src="Scripts/jquery-ui-1.8.20.min.js" type="text/javascript"></script>
<script src="Scripts/jqGrid/4.3.3/i18n/grid.locale-en.js" type="text/javascript"></script>
<script type="text/javascript">
$.jgrid.no_legacy_api = true;
$.jgrid.useJSON = true;
</script>
<script src="Scripts/jqGrid/4.3.3/jquery.jqGrid.min.js" type="text/javascript"></script>
<script src="Scripts/json2.min.js" type="text/javascript"></script>
<script src="Scripts/Common.js" type="text/javascript"></script>
<script src="Scripts/MyPage.js" type="text/javascript"></script>
</head>
<body>
<table id="list"><tr><td></td></tr></table>
<div id="pager"></div>
</body>
</html>
where MyPage.js is
/// <reference path="jquery-1.7.2.js" />
/// <reference path="jqGrid/4.3.3/i18n/grid.locale-en.js" />
/// <reference path="jqGrid/4.3.3/jquery.jqGrid.src.js" />
/// <reference path="Common.js" />
$(function () {
"use strict";
$("#list").jqGrid({
url: "jqGridData.ashx",
colNames: ["First Name", "Last Name", "Birthday"],
colModel: [
{ name: "FirstName", width: 200 },
{ name: "LastName", width: 180 },
{ name: "Birthday", width: 100, formatter: "date", align: "center",
searchoptions: { sopt: ["eq", "ne", "lt", "le", "gt", "ge"], dataInit: function (elem) {
$(elem).datepicker({
dateFormat: "m/d/yy",
minDate: "1/1/1753",
defaultDate: "4/30/1777",
autoSize: true,
changeYear: true,
changeMonth: true,
showButtonPanel: true,
showWeek: true
});
}}
}
],
jsonReader: {
cell: "",
// The Id value will be sent as the 4-th element of row array.
// The value will be not displayed in the grid, but used as rowid
// (the id attribute of the <tr> in the <table>)
id: "3"
},
rowNum: 10,
rowList: [10, 20, 30],
pager: "#pager",
rownumbers: true,
viewrecords: true,
sortname: "Birthday",
sortorder: "desc",
caption: "Famous Mathematicians"
}).jqGrid("navGrid", "#pager", { edit: false, add: false, del: false })
.jqGrid('filterToolbar', { stringResult: true, searchOnEnter: true, defaultSearch: "cn" });
});
and Common.js:
/// <reference path="jquery-1.7.2.js" />
/// <reference path="jqGrid/4.3.3/i18n/grid.locale-en.js" />
/// <reference path="jqGrid/4.3.3/jquery.jqGrid.src.js" />
$.extend($.jgrid.defaults, {
height: "100%",
altRows: true,
altclass: "myAltRowClass",
shrinkToFit: false,
gridview: true,
rownumbers: true,
viewrecords: true,
datatype: "json",
sortable: true,
scrollrows: true,
headertitles: true,
loadui: "block",
viewsortcols: [false, "vertical", true],
prmNames: { nd: null, page: "pageIndex", rows: "rowsPerPage", sort: "sortByColumn", order: "sortOrder", search: "isSearching" },
ajaxGridOptions: { contentType: "application/json" },
ajaxRowOptions: { contentType: "application/json", type: "PUT", async: true },
ajaxSelectOptions: { contentType: "application/json", dataType: "JSON" },
serializeRowData: function (data) {
var propertyName, propertyValue, dataToSend = {};
for (propertyName in data) {
if (data.hasOwnProperty(propertyName)) {
propertyValue = data[propertyName];
if ($.isFunction(propertyValue)) {
dataToSend[propertyName] = propertyValue();
} else {
dataToSend[propertyName] = propertyValue;
}
}
}
return JSON.stringify(dataToSend);
},
resizeStop: function () {
var $grid = $(this.bDiv).find('>:first-child>.ui-jqgrid-btable:last-child'),
shrinkToFit = $grid.jqGrid('getGridParam', 'shrinkToFit'),
saveState = $grid.jqGrid('getGridParam', 'saveState');
$grid.jqGrid('setGridWidth', this.newWidth, shrinkToFit);
if ($.isFunction(saveState)) {
saveState.call($grid[0]);
}
},
gridComplete: function () {
$("#" + this.id + "_err").remove();
},
loadError: function (xhr) {
var response = xhr.responseText, errorDetail, errorHtml, i, l, errorDescription;
if (response.charAt(0) === '[' && response.charAt(response.length - 1) === ']') {
errorDetail = $.parseJSON(xhr.responseText);
var errorText = "";
for (i = 0, l = errorDetail.length; i < l; i++) {
if (errorText.length !== 0) {
errorText += "<hr/>";
}
errorDescription = errorDetail[i];
errorText += "<strong>" + errorDescription.Source + "</strong>";
if (errorDescription.ErrorCode) {
errorText += " (ErrorCode: " + errorDescription.ErrorCode + ")";
}
errorText += ": " + errorDescription.Message;
}
errorHtml = '<div id="errdiv" class="ui-state-error ui-corner-all" style="padding-left: 10px; padding-right: 10px; max-width:' +
($(this).closest(".ui-jqgrid").width() - 20) +
'px;"><p><span class="ui-icon ui-icon-alert" style="float: left; margin-right: .3em;"></span><span>' +
errorText + '</span></p></div>';
$("#" + this.id + "_err").remove();
$(this).closest(".ui-jqgrid").before(errorHtml);
}
}
});
$.extend($.jgrid.search, {
multipleSearch: true,
recreateFilter: true,
closeOnEscape: true,
searchOnEnter: true,
overlay: 0
});
UPDATED: I made some small improvements: included json2.js (see here) to support JSON.stringify in old web browsers, fixed format of date in the jQuery UI Datepicker and included support for DateType and DateType? (System.Nullable<DateType>) in the class Filters. So you can download the current version of the project from the same location.
Related
How to send a zipped file to S3 bucket from Apex?
Folks, I am trying to move data to s3 from Salesforce using apex class. I have been told by the data manager to send the data in zip/gzip format to the S3 bucket for storage cost savings. I have simply tried to do a request.setCompressed(true); as I've read it compresses the body before sending it to the endpoint. Code below: HttpRequest request = new HttpRequest(); request.setEndpoint('callout:'+DATA_NAMED_CRED+'/'+URL+'/'+generateUniqueTimeStampforSuffix()); request.setMethod('PUT'); request.setBody(JSON.serialize(data)); request.setCompressed(true); request.setHeader('Content-Type','application/json'); But no matter what I always receive this: <Error><Code>XAmzContentSHA256Mismatch</Code><Message>The provided 'x-amz-content-sha256' header does not match what was computed.</Message><ClientComputedContentSHA256>fd31b2b9115ef77e8076b896cb336d21d8f66947210ffcc9c4d1971b2be3bbbc</ClientComputedContentSHA256><S3ComputedContentSHA256>1e7f2115e60132afed9e61132aa41c3224c6e305ad9f820e6893364d7257ab8d</S3ComputedContentSHA256> I have tried multiple headers too, like setting the content type to gzip/zip, etc. Any pointers in the right direction would be appreciated.
I had a good amount of headaches attempting to do a similar thing. I feel your pain. The following code has worked for us using lambda functions; you can try modifying it and see what happens. public class AwsApiGateway { // Things we need to know about the service. Set these values in init() String host, payloadSha256; String resource; String service = 'execute-api'; String region; public Url endpoint; String accessKey; String stage; string secretKey; HttpMethod method = HttpMethod.XGET; // Remember to set "payload" here if you need to specify a body // payload = Blob.valueOf('some-text-i-want-to-send'); // This method helps prevent leaking secret key, // as it is never serialized // Url endpoint; // HttpMethod method; Blob payload; // Not used externally, so we hide these values Blob signingKey; DateTime requestTime; Map<String, String> queryParams = new map<string,string>(), headerParams = new map<string,string>(); void init(){ if (payload == null) payload = Blob.valueOf(''); requestTime = DateTime.now(); createSigningKey(secretKey); } public AwsApiGateway(String resource){ this.stage = AWS_LAMBDA_STAGE this.resource = '/' + stage + '/' + resource; this.region = AWS_REGION; this.endpoint = new Url(AWS_ENDPOINT); this.accessKey = AWS_ACCESS_KEY; this.secretKey = AWS_SECRET_KEY; } // Make sure we can't misspell methods public enum HttpMethod { XGET, XPUT, XHEAD, XOPTIONS, XDELETE, XPOST } public void setMethod (HttpMethod method){ this.method = method; } public void setPayload (string payload){ this.payload = Blob.valueOf(payload); } // Add a header public void setHeader(String key, String value) { headerParams.put(key.toLowerCase(), value); } // Add a query param public void setQueryParam(String key, String value) { queryParams.put(key.toLowerCase(), uriEncode(value)); } // Create a canonical query string (used during signing) String createCanonicalQueryString() { String[] results = new String[0], keys = new List<String>(queryParams.keySet()); keys.sort(); for(String key: keys) { results.add(key+'='+queryParams.get(key)); } return String.join(results, '&'); } // Create the canonical headers (used for signing) String createCanonicalHeaders(String[] keys) { keys.addAll(headerParams.keySet()); keys.sort(); String[] results = new String[0]; for(String key: keys) { results.add(key+':'+headerParams.get(key)); } return String.join(results, '\n')+'\n'; } // Create the entire canonical request String createCanonicalRequest(String[] headerKeys) { return String.join( new String[] { method.name().removeStart('X'), // METHOD new Url(endPoint, resource).getPath(), // RESOURCE createCanonicalQueryString(), // CANONICAL QUERY STRING createCanonicalHeaders(headerKeys), // CANONICAL HEADERS String.join(headerKeys, ';'), // SIGNED HEADERS payloadSha256 // SHA256 PAYLOAD }, '\n' ); } // We have to replace ~ and " " correctly, or we'll break AWS on those two characters string uriEncode(String value) { return value==null? null: EncodingUtil.urlEncode(value, 'utf-8').replaceAll('%7E','~').replaceAll('\\+','%20'); } // Create the entire string to sign String createStringToSign(String[] signedHeaders) { String result = createCanonicalRequest(signedHeaders); return String.join( new String[] { 'AWS4-HMAC-SHA256', headerParams.get('date'), String.join(new String[] { requestTime.formatGMT('yyyyMMdd'), region, service, 'aws4_request' },'/'), EncodingUtil.convertToHex(Crypto.generateDigest('sha256', Blob.valueof(result))) }, '\n' ); } // Create our signing key void createSigningKey(String secretKey) { signingKey = Crypto.generateMac('hmacSHA256', Blob.valueOf('aws4_request'), Crypto.generateMac('hmacSHA256', Blob.valueOf(service), Crypto.generateMac('hmacSHA256', Blob.valueOf(region), Crypto.generateMac('hmacSHA256', Blob.valueOf(requestTime.formatGMT('yyyyMMdd')), Blob.valueOf('AWS4'+secretKey)) ) ) ); } // Create all of the bits and pieces using all utility functions above public HttpRequest createRequest() { init(); payloadSha256 = EncodingUtil.convertToHex(Crypto.generateDigest('sha-256', payload)); setHeader('date', requestTime.formatGMT('yyyyMMdd\'T\'HHmmss\'Z\'')); if(host == null) { host = endpoint.getHost(); } setHeader('host', host); HttpRequest request = new HttpRequest(); request.setMethod(method.name().removeStart('X')); if(payload.size() > 0) { setHeader('Content-Length', String.valueOf(payload.size())); request.setBodyAsBlob(payload); } String finalEndpoint = new Url(endpoint, resource).toExternalForm(), queryString = createCanonicalQueryString(); if(queryString != '') { finalEndpoint += '?'+queryString; } request.setEndpoint(finalEndpoint); for(String key: headerParams.keySet()) { request.setHeader(key, headerParams.get(key)); } String[] headerKeys = new String[0]; String stringToSign = createStringToSign(headerKeys); request.setHeader( 'Authorization', String.format( 'AWS4-HMAC-SHA256 Credential={0}, SignedHeaders={1},Signature={2}', new String[] { String.join(new String[] { accessKey, requestTime.formatGMT('yyyyMMdd'), region, service, 'aws4_request' },'/'), String.join(headerKeys,';'), EncodingUtil.convertToHex(Crypto.generateMac('hmacSHA256', Blob.valueOf(stringToSign), signingKey))} )); system.debug(json.serializePretty(request.getEndpoint())); return request; } // Actually perform the request, and throw exception if response code is not valid public HttpResponse sendRequest(Set<Integer> validCodes) { HttpResponse response = new Http().send(createRequest()); if(!validCodes.contains(response.getStatusCode())) { system.debug(json.deserializeUntyped(response.getBody())); } return response; } // Same as above, but assume that only 200 is valid // This method exists because most of the time, 200 is what we expect public HttpResponse sendRequest() { return sendRequest(new Set<Integer> { 200 }); } // TEST METHODS public static string getEndpoint(string attribute){ AwsApiGateway api = new AwsApiGateway(attribute); return api.createRequest().getEndpoint(); } public static string getEndpoint(string attribute, map<string, string> params){ AwsApiGateway api = new AwsApiGateway(attribute); for (string key: params.keySet()){ api.setQueryParam(key, params.get(key)); } return api.createRequest().getEndpoint(); } public class EndpointConfig { string resource; string attribute; list<object> items; map<string,string> params; public EndpointConfig(string resource, string attribute, list<object> items){ this.items = items; this.resource = resource; this.attribute = attribute; } public EndpointConfig setQueryParams(map<string,string> parameters){ params = parameters; return this; } public string endpoint(){ if (params == null){ return getEndpoint(resource); } else return getEndpoint(resource + '/' + attribute, params); } public SingleRequestMock mockResponse(){ return new SingleRequestMock(200, 'OK', json.serialize(items), null); } } }
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); }
Why am I getting Http error 500 when I return too many rows as json in my ajax call?
Here is my code: var context = _contextFactory.Create(GetClient()); var r = from p in context.MyTable.ToList() select p; int tot; var firstPageData = PagedResult(r, 0, 200000, rows => new { rows.Id }, true, out tot); return Json(new { result = "ok", rows = firstPageData }, JsonRequestBehavior.AllowGet); The first and second parameter to PagedResult() (0 and 200000) are the pagenumber and number of rows to return. This is returning http error 500. But when I change the 2nd parameter to PagedResult() to return only 20 rows, it's working fine. Like this: var context = _contextFactory.Create(GetClient()); var r = from p in context.MyTable.ToList() select p; int tot; var firstPageData = PagedResult(r, 0, 20, rows => new { rows.Id }, true, out tot); return Json(new { result = "ok", rows = firstPageData }, JsonRequestBehavior.AllowGet); Is it I am getting this error because I am returning too many rows that http can't handle? Or are there configurations I need to make so I can return these too many rows? Thanks,
use a custom JsonResult Class for ASP.Net MVC to avoid MaxJsonLength Exceeded Exception. public class LargeJsonResult : JsonResult { const string JsonRequest_GetNotAllowed = "This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet."; public LargeJsonResult() { MaxJsonLength = 1024000; RecursionLimit = 100; } public int MaxJsonLength { get; set; } public int RecursionLimit { get; set; } public override void ExecuteResult( ControllerContext context ) { if( context == null ) { throw new ArgumentNullException( "context" ); } if( JsonRequestBehavior == JsonRequestBehavior.DenyGet && String.Equals( context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase ) ) { throw new InvalidOperationException( JsonRequest_GetNotAllowed ); } HttpResponseBase response = context.HttpContext.Response; if( !String.IsNullOrEmpty( ContentType ) ) { response.ContentType = ContentType; } else { response.ContentType = "application/json"; } if( ContentEncoding != null ) { response.ContentEncoding = ContentEncoding; } if( Data != null ) { JavaScriptSerializer serializer = new JavaScriptSerializer() { MaxJsonLength = MaxJsonLength, RecursionLimit = RecursionLimit }; response.Write( serializer.Serialize( Data ) ); } } } and use it as return new LargeJsonResult { Data = Your Data, JsonRequestBehavior = `System.Web.Mvc.JsonRequestBehavior.AllowGet };`
e.GetListSourceFieldValue returns null in the CustomUnboundColumnData event handler
I am using DevExpress control within an ASP.NET MVC 4 project. I am using unbound columns in the GridView extension for ASP.NET MVC. In the CustomUnboundColumnData event handler, the e.GetListSourceFieldValue always returns null for me. I then tried getting the value directly from the model instead of calling this method (please see the commented line just above the call to the method) but even though that worked, it had side-effects, which I won't get into just now. I am using ASP.NET MVC 4 with Visual Web Developer Express 2010 edition. I am using DevExpress extensions for MVC v12.2.10.0. My OS is Windows 7, 64-bit. However, the extensions I am using are 32-bit only. I cannot ship my whole solution as it is broken down into multiple projects, most of which have lots of IP code I've written for my client. But here are the relevant pieces from my code. Index.cshtml (Razor View Engine) ------------------------------------------------------------------- #model List<GlobalizationUI.Presentation.ViewModels.StringTableRow> #{ ViewBag.Title = "Strings"; } <div id = "pageCaption">Strings</div> #Html.Partial("_StringsPartial", Model) _StringsPartial.cshtml (Razor View Engine) ------------------------------------------------------------------- #using System.Web.UI.WebControls; #using System.Data; #model List<GlobalizationUI.Presentation.ViewModels.StringTableRow> #Html.DevExpress().GridView(settings => { settings.Name = "gvStrings"; settings.CallbackRouteValues = new { Controller = "Strings", Action = "StringsPartial" }; settings.Width = 1200; settings.SettingsPager.Position = PagerPosition.TopAndBottom; settings.SettingsPager.FirstPageButton.Visible = true; settings.SettingsPager.LastPageButton.Visible = true; settings.SettingsPager.PageSizeItemSettings.Visible = true; settings.SettingsPager.PageSizeItemSettings.Items = new string[] { "10", "20", "50", "100", "200" }; settings.SettingsPager.PageSize = 50; settings.Settings.ShowFilterRow = true; settings.Settings.ShowFilterRowMenu = true; settings.CommandColumn.Visible = true; settings.CommandColumn.ClearFilterButton.Visible = true; settings.Settings.ShowHeaderFilterButton = true; settings.KeyFieldName = "ResourceKeyId"; settings.Columns.Add("Key"); var categoryColumn = settings.Columns.Add("CategoryId", "Category"); categoryColumn.ColumnType = MVCxGridViewColumnType.ComboBox; var categoryColumnEditProperties = categoryColumn.PropertiesEdit as ComboBoxProperties; categoryColumnEditProperties.DataSource = ViewBag.AllCategories; categoryColumnEditProperties.TextField = "Name"; categoryColumnEditProperties.ValueField = "Id"; categoryColumnEditProperties.ValueType = typeof(long); if (Model != null && Model.Count > 0 && Model[0] != null && Model[0].StringValues != null && Model[0].StringValues.Count > 0) { foreach (var kvp in Model[0].StringValues) { settings.Columns.Add(col => { col.FieldName = kvp.CultureShortName; col.Caption = kvp.CultureShortName; col.UnboundType = DevExpress.Data.UnboundColumnType.Object; col.SetDataItemTemplateContent(container => { ViewContext.Writer.Write(DataBinder.Eval(container.DataItem, col.FieldName + ".StringValue")); }); col.SetEditItemTemplateContent(container => { Html.DevExpress().TextBox(s => { s.Name = string.Format("txt{0}", kvp.CultureShortName); }).Bind(kvp.StringValue).Render(); }); }); } } settings.CustomUnboundColumnData = (sender, e) => { var fixedColumns = new List<string> { "ResourceKeyId", "Key", "CategoryId" }; if (!fixedColumns.Contains(e.Column.FieldName)) { if (e.IsGetData) { try { // var values = Model[e.ListSourceRowIndex].StringValues; var values = e.GetListSourceFieldValue(e.ListSourceRowIndex, "StringValues") as IList<GlobalizationUI.Presentation.ViewModels.CultureNameAndStringValue>; if (values != null) { var value = values.FirstOrDefault(pair => pair.CultureShortName == e.Column.FieldName); var defaultValue = default(GlobalizationUI.Presentation.ViewModels.CultureNameAndStringValue); e.Value = value.Equals(defaultValue) ? defaultValue : new GlobalizationUI.Presentation.ViewModels.CultureNameAndStringValue(); } } catch (Exception ex) { System.Diagnostics.Debugger.Break(); System.Diagnostics.Debug.Print(ex.ToString()); } } } }; foreach (GridViewDataColumn column in settings.Columns) { column.Settings.HeaderFilterMode = HeaderFilterMode.CheckedList; } settings.SettingsEditing.AddNewRowRouteValues = new { Controller = "Strings", Action = "CreateNew" }; settings.SettingsEditing.UpdateRowRouteValues = new { Controller = "Strings", Action = "Edit" }; settings.SettingsEditing.DeleteRowRouteValues = new { Controller = "Strings", Action = "Delete" }; settings.SettingsEditing.Mode = GridViewEditingMode.Inline; settings.SettingsBehavior.ConfirmDelete = true; settings.CommandColumn.Visible = true; settings.CommandColumn.NewButton.Visible = true; settings.CommandColumn.EditButton.Visible = true; settings.CommandColumn.UpdateButton.Visible = true; settings.CommandColumn.DeleteButton.Visible = true; }).Bind(Model).GetHtml() StringsController ------------------------------------------------------------------- using System.Data; using System.Web.Mvc; using GlobalizationUI.BusinessObjects; using Resources.BaseServices.Caching; using System.Collections.Generic; using System.ComponentModel; using GlobalizationUI.Presentation.ViewModels; using Resources.Util; namespace GlobalizationUI.Presentation.Controllers { public class StringsController : Controller { private static string CacheKey_StringTable = "CacheKey_StringTable"; private static string CacheKey_AllCategories = "CacheKey_AllCategories"; private static object padLock = new object(); public ActionResult Index() { var stringTable = GetStringTable(); ViewBag.AllCategories = GetCategoryList(); return View(stringTable); } public ActionResult StringsPartial() { var stringTable = GetStringTable(); ViewBag.AllCategories = GetCategoryList(); return PartialView("_StringsPartial", stringTable); } [HttpPost] public ActionResult CreateNew(StringTableRow row) { System.Diagnostics.Debugger.Break(); foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(row)) { System.Diagnostics.Debug.Print(prop.Name); } return Content("Hello, there!"); } [HttpPost] public ActionResult Edit(DataRow row) { return new EmptyResult(); } [HttpPost] public ActionResult Delete(long resourceKeyId) { return new EmptyResult(); } private IEnumerable<Category> GetCategoryList() { lock (padLock) { if (CacheManager.Contains(CacheKey_AllCategories)) { return CacheManager.Get<IEnumerable<Category>>(CacheKey_AllCategories); } } var list = Category.All; lock (padLock) { CacheManager.Add(CacheKey_AllCategories, list); } return list; } private List<StringTableRow> GetStringTable() { List<StringTableRow> stringTable; lock (padLock) { if (CacheManager.Contains(CacheKey_StringTable)) { return CacheManager.Get<List<StringTableRow>>(CacheKey_StringTable); } } stringTable = new StringTable().ToListOfStringTableRows(); lock (padLock) { CacheManager.Add(CacheKey_StringTable, stringTable); } return stringTable; } } } View Models ------------------------------------------------------------------- using System.Collections.Generic; namespace GlobalizationUI.Presentation.ViewModels { public class StringTableRow { public long ResourceKeyId { get; set; } public string Key { get; set; } public long CategoryId { get; set; } public List<CultureNameAndStringValue> StringValues { get; set; } } } namespace GlobalizationUI.Presentation.ViewModels { public class CultureNameAndStringValue { public CultureNameAndStringValue() : this(null, null) { } public CultureNameAndStringValue(string cultureShortName, string stringValue) { CultureShortName = cultureShortName; StringValue = stringValue; } public string CultureShortName { get; set; } public string StringValue { get; set; } } } Model: ------------------------------------------------------------------- using System.Data; using GlobalizationUI.Data; namespace GlobalizationUI.BusinessObjects { public class StringTable : DataTable { public StringTable() { var sql = #" declare #stmt nvarchar(max) select #stmt = isnull(#stmt + ', ', '') + 'max(case when s.CultureId = ' + cast(c.Id as nvarchar(max)) + ' then s.ResourceValue end) as ' + quotename(c.ShortName) from Culture as c where c.Supported = 1 select #stmt = ' select rk.Id AS ResourceKeyId, rk.Name AS [Key], c.Id AS CategoryId, c.Name as CategoryName, ' + #stmt + ' from StringCategory as sc LEFT OUTER join Category as c on c.Id = sc.CategoryId RIGHT OUTER JOIN ResourceKey as rk on rk.Id = sc.ResourceKeyId inner join Strings as s on s.ResourceKeyId = rk.Id group by rk.Id, rk.Name, c.Id, c.Name ' exec sp_executesql #stmt = #stmt;"; this.Merge(Database.DefaultDatabase.GetDataTable(sql)); } } } Model to View Model conversion: ------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Data; using System.Data.SqlTypes; namespace GlobalizationUI.Presentation.ViewModels { public static class DataTableExtensions { public static List<StringTableRow> ToListOfStringTableRows(this DataTable dataTable) { var ret = new List<StringTableRow>(); if (dataTable == null || dataTable.Rows.Count == 0) return ret; foreach (DataRow row in dataTable.Rows) { StringTableRow stringTableRow = new StringTableRow(); foreach (DataColumn column in dataTable.Columns) { if (string.Compare(column.ColumnName, "ResourceKeyId", true) == 0) { stringTableRow.ResourceKeyId = (long)row[column.ColumnName]; } else if (string.Compare(column.ColumnName, "Key", true) == 0) { stringTableRow.Key = (string)row[column.ColumnName]; } else if (string.Compare(column.ColumnName, "CategoryId", true) == 0) { var categoryId = row[column.ColumnName]; stringTableRow.CategoryId = categoryId == DBNull.Value ? 0 : (long)categoryId; } else if (string.Compare(column.ColumnName, "CategoryName", true) == 0) { continue; } else { if (stringTableRow.StringValues == null) stringTableRow.StringValues = new List<CultureNameAndStringValue>(); stringTableRow.StringValues.Add(new CultureNameAndStringValue(column.ColumnName, (string)row[column.ColumnName])); } } ret.Add(stringTableRow); } return ret; } } } The user interface is supposed to look somewhat like the the picture shown above. The number of columns returned by the SQL query is variable depending upon the number of cultures supported by a particular installation/deployment/business client. Hence the need for using unbound columns. I took this picture not through this code but through an older version of my code when I bound data directly to a System.Data.DataTable and did not use any unbound columns. That was all well until I had to edit the data in the actions at the MVC/server side. So, I switched from using a DataTable to a POCO and used unbound columns for all cultures. Kindly help.
Okay, though I posted this question only 2 hours or so ago, I've had this trouble for over 8 hours now and have been trying various ways to solve this problem. And just now, one of the things I did made this problem go away. Here it is. If you are binding your DevExpress GridViewExtension for ASP.NET MVC to a custom POCO like mine, and that POCO has one or more members that are collections of any kind, then, you must and absolutely must initialize those properties that represent collections in the constructor of your POCO. For e.g., in my case, the model was a list of StringTableRow's, where StringTableRow was a POCO. In the StringTableRow class, I had a property named StringValues which was of type IList<CultureNameAndStringValue>, which is a collection. Therefore, for my code to work, I initialized the StringValues property in the construct of my StringTableRow class and everything started to work. using System.Collections.Generic; namespace GlobalizationUI.Presentation.ViewModels { public class StringTableRow { public StringTableRow() { // I added this ctor and initialized the // StringValues property and the broken // custom binding to unbound columns started // to work. StringValues = new List<CultureNameAndStringValue>(); } public long ResourceKeyId { get; set; } public string Key { get; set; } public long CategoryId { get; set; } public IList<CultureNameAndStringValue> StringValues { get; set; } } }
json object and Web method Invalid Web services call missing value parameter
I have Jquery sortable UI I have web services to update the order of reminder when user update the reminder orders I know it is problem passing json data to web services but could not solve it Error: Invalid Web services call missing value parameter: rlist at System.Web.Script.Services.WebServiceMethodData.CallMethod(Object target, IDictionary2 parameters) at System.Web.Script.Services.WebServiceMethodData.CallMethodFromRawParams(Object target, IDictionary2 parameters) at System.Web.Script.Services.RestHandler.InvokeMethod(HttpContext context, WebServiceMethodData methodData, IDictionary`2 rawParams) at System.Web.Script.Services.RestHandler.ExecuteWebServiceCall(HttpContext context, WebServiceMethodData methodData) Web Services using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Services; using Compudata_ProjectManager.CodeFile.BOL; using System.Data.SqlClient; using System.Web.Script.Services; namespace Compudata_ProjectManager.WebServices { /// <summary> /// Summary description for remindersWebService /// </summary> [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(false)] [ScriptService] // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. // [System.Web.Script.Services.ScriptService] public class remindersWebService : System.Web.Services.WebService { public class ReminderDTO { public int Id { get; set; } public int Order { get; set; } } [WebMethod] [ScriptMethod(ResponseFormat = ResponseFormat.Json)] public string UpdateOrder(List<ReminderDTO> rList) { //CompuData_ProjectManagerConfiguration.DbconnctionString; using (SqlConnection connectionString = new SqlConnection(CompuData_ProjectManagerConfiguration.DbconnctionString)) { foreach (var r in rList) { string sSQL = "UPDATE [TaskManagementSystem_DB].[dbo].[Reminders] SET [reminderOrder] = " + r.Order.ToString() + "where reminderID = " + r.Id; SqlCommand cmd = new SqlCommand(sSQL, connectionString); try { cmd.ExecuteNonQuery(); } catch (SqlException) { return "falied"; } } return "save"; } } } } javascript $(function () { $("#sortable").sortable({ placeholder: "vacant", update: function (e, ui) { //process each li //create vars var orderArray = []; var wrap = {}; $("#sortable li").each(function () { //build ReminderObject var reminderObject = { Id: $(this).attr("id"), Order: $(this).find("input[type='hidden']").val() }; //add object to array orderArray.push(reminderObject); }); wrap.d = orderArray //pass to server $.ajax({ type: "POST", url: "../WebServices/remindersWebService.asmx/UpdateOrder", data: JSON.stringify(wrap), processData: false, contentType: "application/json; charset=utf-8", success: function (data) { if (data.d === "saved") { document.write("Save ok"); } else { document.write("Save failed"); } }, error: function (xhr, status, error) { var err = eval("(" + xhr.responseText + ")"); console.log(err.StackTrace); alert(err.Message); } }); } //end of update function }); $("#sortable").disableSelection(); $("input[type=checkbox]").on("click", function () { $(this).nextAll().toggleClass("hidden"); }); }); </script>
Try sending Id and Order as integers as they are expected to be. var reminderObject = { Id: parseInt($(this).attr("id"), 10), Order: parseInt($(this).find("input[type='hidden']").val(), 10) }; Also change wrap.d = orderArray to wrap.rList = orderArray as rList is the expected parameter.