Это своего рода продолжение предыдущего вопроса.
Теперь я пытаюсь вызвать веб-службу с поддержкой AJAX, которую я определил в приложении ASP.NET MVC (т.е. MovieService.svc). Но служба никогда не вызывается в моей getMovies функции javascript.
Этот же метод вызова веб-службы AJAX работает нормально, если я попробую его в приложении, отличном от ASP.NET MVC, поэтому я задаюсь вопросом, могут ли маршруты ASP MVC каким-то образом мешать чему-то, когда он пытается сделать вызов веб-службы AJAX .
Вы хоть понимаете, почему мне не звонят в мою веб-службу? Код ниже.
<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" />
Вот мой код RegisterRoutes:
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
);
}
Вот как выглядит мой класс MovieService:
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();
}
}
}
Ответ 1 · рейтинг 11 · Oleg
Ваша основная проблема в том, что вы используете не абсолютные URL-адреса в вызове ajax. Неправильные записи в web.config также могут создавать проблемы. Кроме того, вы используете datatype: getMovies вместо datatype: 'json' и postData: yourData. Способ с datatype в качестве функций существует (см. http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data#function), но начиная с jqGrid 3.6.5 у вас есть более прямой путь внутри jsonReader для чтения данных, возвращаемых с веб-сервера.
ОБНОВЛЕНО: мне кажется, что описание функций редактирования я сделаю позже и объясню здесь, как получить данные JSON и заполнить их внутри jqGrid.
Прежде всего, jqGrid может запрашивать данные JSON с сервера. Поэтому нам не нужно делать отдельный jQuery.ajax звонок. Вам нужно только определить URL-адрес, указывающий на сервер, и определить некоторые дополнительные jQuery.ajax параметры, которые вы предпочитаете. Вы не публикуете в своем вопросе определение класса Movie. Поэтому я сам определяю это следующим образом
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; }
}
Следует отметить, что Microsoft сериализует тип DataTime не как читаемую строку даты, а как строку /Date(utcDate)/, где utcDate - это число (см. jQuery.param () - не сериализует ли объекты даты javascript?). Чтобы вначале было меньше проблем, я определяю ReleaseDate как строку.
Метод IList<Movie> GetMovies() возвращает данные JSON в виде массива объектов Movie. Итак, jqGrid в ответ на HTTP GET запрос получает от MovieService.svc/GetMovies URL следующие данные:
[{"Id":1, "Name": "E.T.", "Director": "Steven Spielberg",...},{...},...]
Могу сказать, что это нетипичный формат данных, которые ждут jqGrid (сравните с http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data#json_data). Чтобы иметь возможность размещать данные внутри jqGrid, мы должны определить jsonReader. Итак, мы делаем следующее
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 });
ПРИМЕЧАНИЕ: я удаляю из примера любые параметры сортировки, потому что в случае запроса данных JSON параметр сортировки будет только отправлен на сервер (некоторые дополнительные параметры добавляют URL-адрес сервера), и сервер должен вернуть отсортированные данные. Для получения дополнительной информации см. Описание параметра prmNames на http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options и описание параметра sopt в http://www.trirand.com/jqgridwiki/doku.php?id=wiki:singe_searching.
Что касается datatype: 'json', мы определяем параметр dataType: 'json' для jQuery.ajax (не путайте регистр внутри параметра datatype). Имена всех полей внутри colModel мы определяем точно так же, как имена полей внутри наших объектов JSON. Некоторые дополнительные параметры viewrecords, rownumbers, sortable и headertitles не очень важны в этом примере, я выбрал их, потому что 1) они мне нравятся и 2) я установил rowNum: 0, чтобы параметры rownumbers: true работали правильно и не отображали отрицательные номера строк, начинающиеся с -5, если rowNum: 5, как в исходном примере.
С помощью ajaxGridOptions: { contentType: "application/json" } мы определяем дополнительные параметры, которые будут напрямую перенаправлены на jQuery.ajax.
Самая сложная часть этого примера -
jsonReader: { repeatitems: false, id: "Id", root: function(obj) { return obj; }}
Он определяет, что id всех строк имеет имя "Id" (см. Определение class Movie). "repeatitems: false" означает, что каждое поле данных мы хотим идентифицировать по имени поля (определенному в colModel) вместо определения по умолчанию для каждой позиции. Определение root немного странно, но оно определяет, как найти корень строк внутри данных JSON. Формат данных JSON по умолчанию следующий
{
total: "xxx",
page: "yyy",
records: "zzz",
rows : [
{id:"1", cell:["cell11", "cell12", "cell13"]},
{id:"2", cell:["cell21", "cell22", "cell23"]},
...
]
}
а корень строк определяется как root: "rows". Таким образом, если данные JSON присвоены переменной res, корень может быть возвращен как res.rows. Чтобы позволить jqGrid читать наши данные, мы определяем jsonReader.root как функцию (эта функция существует с jqGrid 3.6.5, см. http://www.trirand.com/jqgridwiki/doku.php?id=wiki:change#adds_and_changes). Вы можете убедиться, что этот странный метод работает. Типичные дополнительные параметры page, total (lastpage) и records не существуют в наших данных JSON, и они будут инициализированы следующим образом page:0, total:1, records:0. Таким образом, мы не можем выполнять подкачку данных. Вы можете расширить jsonReader функциями, определяющими page, total и records (также как функции), например
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; }
}
что завершит наш jsonReader. Тогда установка rowNum: 0 больше не понадобится.
Я показал этот способ только для того, чтобы показать гибкость jqGrid. Вы должны использовать описанный способ только в том случае, если вы получаете доступ к веб-серверу, который вы не можете изменить. jqGrid имеет такие функции, как разбиение по страницам, сортировка и два вида поиска (больше как фильтрация с помощью WHERE в соответствующем SELECT) данных: простой и расширенный . Если мы хотим иметь эти замечательные функции внутри jqGrid на наших веб-страницах, мы должны определить в веб-службе дополнительный метод, например
[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)
где 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; }
}
Или, если мы хотим использовать наиболее компактную форму данных, передаваемых от сервера к клиенту, тогда
// 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.
}
(вы можете узнать больше об этом виде передачи данных на http://www.trirand.com/blog/jqgrid/jqgrid.html, если вы выберете в левой части дерева "Сопоставление данных", а затем "Оптимизация данных")
PS: Подробнее о jsonReader вы можете узнать на http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data#json_data. Один мой старый ответ Отображение данных JSON в JQGrid также может быть интересным для ты.
ОБНОВЛЕНО 2. Поскольку вы не отметили ответ как принятый, у вас останутся проблемы. Итак, я создал новый проект в Visual Studio 2010, который демонстрирует то, что я написал. Вы можете загрузить исходный код с http://www.ok-soft-gmbh.com/jqGrid/jQueryMVC.zip. Сравните с вашим проектом, особенно с частью с полным URL-адресом в качестве параметра jqGrid и частью web.config, описывающей интерфейс службы WCF.
ОБНОВЛЕНО 3: пользуюсь VS2010 не так давно. Так что я мог очень быстро понизить его до VS2008. Таким образом, почти такой же код работает в Visual Studio 2008, но с ASP.NET MVC 2.0 вы можете загрузить с http://www.ok-soft-gmbh.com/jqGrid/VS2008jQueryMVC.zip. Код в ASP.NET MVC 1.0 должен быть таким же, но GUID из файла проекта и некоторые строки из Web.config должны быть исправлены (см. http://www.asp.net/learn/whitepapers/aspnet-mvc2-upgrade-notes).