jquery with ASP.NET MVC - calling ajax enabled web service
This is a bit of a continuation of a previous question.
Now I'm trying to make a call to an AJAX enabled web service which I have defined within the ASP.NET MVC application (i.e. the MovieService.svc
). But the service is never开发者_C百科 being called in my getMovies
javascript function.
This same technique of calling the AJAX web service works ok if I try it in a non ASP.NET MVC application, so it makes me wonder if maybe the ASP MVC routes are interfering with things somehow when it tries to make the AJAX web service call.
Do you have any idea why my web service isn't getting called? Code below.
<script src="<%= ResolveClientUrl("~/scripts/jquery-1.4.2.min.js") %>" type="text/javascript"></script>
<script src="<%= ResolveClientUrl("~/scripts/grid.locale-en.js") %>" type="text/javascript"></script>
<script src="<%= ResolveClientUrl("~/scripts/jquery-ui-1.8.1.custom.min.js") %>"
type="text/javascript"></script>
<script src="<%= ResolveClientUrl("~/scripts/jquery.jqGrid.min.js") %>" type="text/javascript"></script>
<script type="text/javascript">
var lastsel2;
function successFunction(jsondata) {
debugger
var thegrid = jQuery("#editgrid");
for (var i = 0; i < jsondata.d.length; i++) {
thegrid.addRowData(i + 1, jsondata.d[i]);
}
}
function getMovies() {
debugger
// ***** the MovieService#GetMovies method never gets called
$.ajax({
url: 'MovieService.svc/GetMovies',
data: "{}", // For empty input data use "{}",
dataType: "json",
type: "GET",
contentType: "application/json; charset=utf-8",
success: successFunction
});
}
jQuery(document).ready(function() {
jQuery("#editgrid").jqGrid({
datatype: getMovies,
colNames: ['id', 'Movie Name', 'Directed By', 'Release Date', 'IMDB Rating', 'Plot', 'ImageURL'],
colModel: [
{ name: 'id', index: 'Id', width: 55, sortable: false, hidden: true, editable: false, editoptions: { readonly: true, size: 10} },
{ name: 'Movie Name', index: 'Name', width: 250, editable: true, editoptions: { size: 10} },
{ name: 'Directed By', index: 'Director', width: 250, align: 'right', editable: true, editoptions: { size: 10} },
{ name: 'Release Date', index: 'ReleaseDate', width: 100, align: 'right', editable: true, editoptions: { size: 10} },
{ name: 'IMDB Rating', index: 'IMDBUserRating', width: 100, align: 'right', editable: true, editoptions: { size: 10} },
{ name: 'Plot', index: 'Plot', width: 150, hidden: false, editable: true, editoptions: { size: 30} },
{ name: 'ImageURL', index: 'ImageURL', width: 55, hidden: true, editable: false, editoptions: { readonly: true, size: 10} }
],
pager: jQuery('#pager'),
rowNum: 5,
rowList: [5, 10, 20],
sortname: 'id',
sortorder: "desc",
height: '100%',
width: '100%',
viewrecords: true,
imgpath: '/Content/jqGridCss/redmond/images',
caption: 'Movies from 2008',
editurl: '/Home/EditMovieData/',
caption: 'Movie List'
});
$("#bedata").click(function() {
var gr = jQuery("#editgrid").jqGrid('getGridParam', 'selrow');
if (gr != null)
jQuery("#editgrid").jqGrid('editGridRow', gr, { height: 280, reloadAfterSubmit: false });
else
alert("Hey dork, please select a row");
});
});
</script>
<h2>
<%= Html.Encode(ViewData["Message"]) %></h2>
<p>
To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">
http://asp.net/mvc</a>.
</p>
<table id="editgrid">
</table>
<div id="pager" style="text-align: center;">
</div>
<input type="button" id="bedata" value="Edit Selected" />
Here's my RegisterRoutes code:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("*MovieService.svc*");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
Here's what my MovieService class looks like:
namespace jQueryMVC
{
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MovieService
{
// Add [WebGet] attribute to use HTTP GET
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
public IList<Movie> GetMovies()
{
return Persistence.GetMovies();
}
}
}
Your main problem is that you use not absolute URLs in the ajax
call. Wrong entries in web.config
can make also problems. Moreover you use datatype: getMovies
instead of datatype: 'json'
and postData: yourData
. The way with datatype
as functions exist (see http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data#function), but since jqGrid 3.6.5 you have more direct way inside of jsonReader
to read the data returned from web server.
UPDATED: It seems to me that describing of editing features I'll make later and explain here just how to get JSON data and fill there inside of jqGrid.
First of all jqGrid can request itself the JSON data from the server. So we don’t need to make a separate jQuery.ajax
call. You need only define a URL which point to the server and define some additional jQuery.ajax
parameters which you prefer.
You don’t post in your question the definition of the Movie
class. So I define it myself like following
public class Movie {
public int Id { get; set; }
public string Name { get; set; }
public string Director { get; set; }
public string ReleaseDate { get; set; }
public string IMDBUserRating { get; set; }
public string Plot { get; set; }
public string ImageURL { get; set; }
}
You should remark, that Microsoft serialize DataTime
type not as a readable date string but as a string /Date(utcDate)/
, where utcDate
is this number
(see jQuery.param() - doesn't serialize javascript Date objects?). To make fewer problems at the beginning I define ReleaseDate
as string.
Method IList<Movie> GetMovies()
returns JSON data like an array of objects Movie
. So jqGrid as a response to HTTP GET
request receive from the MovieService.svc/GetMovies
URL the data like following:
[{"Id":1, "Name": "E.T.", "Director": "Steven Spielberg",...},{...},...]
I can say that it is not typical format of data, which are waiting jqGrid (compare with http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data#json_data). To be able to place the data inside of jqGrid we must define a jsonReader
. So we do following
jQuery("#editgrid").jqGrid({
url: '<%= Url.Content("~/MovieService.svc/GetMovies")%>',
datatype: 'json',
ajaxGridOptions: { contentType: "application/json" },
jsonReader: { repeatitems: false, id: "Id", root: function(obj) { return obj; }},
headertitles: true,
sortable: true,
colNames: ['Movie Name', 'Directed By', 'Release Date',
'IMDB Rating', 'Plot', 'ImageURL'],
colModel: [
{ name: 'Name', width: 250},
{ name: 'Director', width: 250, align: 'right' },
{ name: 'ReleaseDate', width: 100, align: 'right' },
{ name: 'IMDBUserRating', width: 100, align: 'right' },
{ name: 'Plot', width: 150 },
{ name: 'ImageURL', width: 55, hidden: true }
],
pager: jQuery('#pager'),
pginput: false,
rowNum: 0,
height: '100%',
viewrecords: true,
rownumbers: true,
caption: 'Movies from 2008'
}).jqGrid('navGrid', '#pager', { add: false, edit: false, del: false, search: false });
REMARK: I remove from the example any sorting parameters, because in case of request of JSON data, the sorting parameter will be only send to server (some additional parameters append the server URL) and server must give back sorted data. For more information see description of prmNames
parameter on http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options and description of sopt
parameter on http://www.trirand.com/jqgridwiki/doku.php?id=wiki:singe_searching.
With respect of datatype: 'json'
we define dataType: 'json'
parameter of jQuery.ajax
(don’t confuse the case inside of datatype
parameter). The names of all fields inside of colModel
we define exact the same as the field names inside our JSON objects. Some additional parameters viewrecords
, rownumbers
, sortable
and headertitles
are not very important in this example, I choosed there because 1) I like there and 2) I set rowNum: 0
to make possible the options rownumbers: true
works correct and not show us negative row numbers started with -5 if rowNum: 5
like in your original example.
With ajaxGridOptions: { contentType: "application/json" }
we define additional parameters which will be direct forwarded to the jQuery.ajax
.
The most complex part of this example is
jsonReader: { repeatitems: false, id: "Id", root: function(obj) { return obj; }}
It defines that id of all rows have the name "Id" (see definition of the class Movie
). "repeatitems: false
" say that every data field we want identify by the field name (defined in colModel
) instead of default definition per position. The definition of root
is a little strange, but it defines how to find the root of rows inside of JSON data. Default format of JSON data is following
{
total: "xxx",
page: "yyy",
records: "zzz",
rows : [
{id:"1", cell:["cell11", "cell12", "cell13"]},
{id:"2", cell:["cell21", "cell22", "cell23"]},
...
]
}
and the root of rows are defined as root: "rows"
. So if the JSON data assigned to the variable res
, the root can be returned as res.rows
. To allow jqGrid to read our data we define jsonReader.root
as a function (this feature exist since jqGrid 3.6.5 see http://www.trirand.com/jqgridwiki/doku.php?id=wiki:change#additions_and_changes). You can verify that this strange method work. The typical additional parameters page
, total
(lastpage
) and records
are not exist inside of our JSON data and they will be initialized as following page:0, total:1, records:0
. So we are not able to make data paging. You can expand jsonReader
with functions defining page
, total
and records
(also as functions) like
jsonReader: {
repeatitems: false,
id: "Id",
root: function (obj) { return obj; },
page: function (obj) { return 1; },
total: function (obj) { return 1; },
records: function (obj) { return obj.length; }
}
which will complete our jsonReader. Then setting of rowNum: 0
will not more needed.
I showed this way only to show the flexibility of jqGrid. You should use described way only if you access a web server which you cannot change. jqGrid has features like paging, sorting and two kind of searching (more as filtering with WHERE in the corresponding SELECT) of data: simple and advanced. If we want have these nice features inside of jqGrid on our web pages we should define in Web Service an additional method like
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json,
UriTemplate = "jqGridGetTestbereiche?_search={_search}&page={page}&"+
"rows={rows}&sidx={sortIndex}&sord={sortDirection}&"+
"searchField={searchField}&searchString={searchString}&"+
"searchOper={searchOper}&filters={filters}")]
public jqGridTable jqGridGetMovies(
int page, int rows, string sortIndex, string sortDirection,
string _search, string searchField, string searchString,
string searchOper, string filters)
where jqGridTable
public class jqGridTable
{
public int total { get; set; } // total number of pages
public int page { get; set; } // current zero based page number
public int records { get; set; } // total number of records
public List<jqGridRow> rows { get; set; }
}
public class jqGridRow
{
public string id { get; set; }
public List<string> cell { get; set; }
}
Or if we want use the most compact form of data transferred from server to client then
// jsonReader: { repeatitems : true, cell:"", id: "0" }
public class jqGridTable {
public int total { get; set; } // total number of pages
public int page { get; set; } // current zero based page number
public int records { get; set; } // total number of records
public List<List<string>> rows { get; set; }// first element in every row must be id of row.
}
(you can read more about this kind of data transfer on http://www.trirand.com/blog/jqgrid/jqgrid.html if you choose on the left tree part "Data Mapping" and then "Data Optimization")
P.S.: About jsonReader you can read more on http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data#json_data. One my old answer Mapping JSON data in JQGrid can be also interesting for you.
UPDATED 2: Because you don't mark the answer as accepted, you stay have some problems. So I created a new Project in Visual Studio 2010 which demonstrate what I written. You can download the source from http://www.ok-soft-gmbh.com/jqGrid/jQueryMVC.zip. Compare with your project, especially the part with full url as a parameter of jqGrid and a part of web.config which describes WCF service interface.
UPDATED 3: I use VS2010 not so long time. So I could very quickly downgrade this to VS2008. So almost the same code working working in Visual Studio 2008, but with ASP.NET MVC 2.0 you can download from http://www.ok-soft-gmbh.com/jqGrid/VS2008jQueryMVC.zip. The code in ASP.NET MVC 1.0 should be the same, but a GUID from the project file and some strings from Web.config should be patched (see http://www.asp.net/learn/whitepapers/aspnet-mvc2-upgrade-notes).
That is because the registered route in the global.asax, will not be recognizing this .svc file. it will try to search for that controller with the action getmovies and will fail. try out debugging using firebug. you can fix this by ignoring this route in the global.asax
I encountered the same issue. I came to the conclusion that the routes were interfering with the service call. Have you tried Phil Haack's Route Debugger? It's saved my bacon a couple times.
In the ended, I created an endpoint off one of the controllers.
Oleg,
Do you have the example you were talking about as i am working with jqgrid/asp.net mvc and a restful service and having a bugger of a time. It would help out seeing an example as i am at a wall. Thx
SEM
精彩评论