jquery с ASP.NET MVC - вызов веб-службы с поддержкой ajax - PullRequest
2 голосов
/ 14 мая 2010

Это немного продолжение предыдущего вопроса.

Теперь я пытаюсь позвонить в веб-службу с поддержкой 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();
        }

    }
}

Ответы [ 4 ]

11 голосов
/ 14 мая 2010

Ваша главная проблема в том, что вы используете не абсолютные 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 получает от URL MovieService.svc/GetMovies данные, подобные следующим:

 [{"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 });

REMARK : я удаляю из примера любые параметры сортировки, потому что в случае запроса данных 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" } мы определяем дополнительные параметры, которые будут direct пересылаться в jQuery.ajax.

Самая сложная часть этого примера -

jsonReader: { repeatitems: false, id: "Id", root: function(obj) { return obj; }}

Он определяет, что id всех строк имеет имя "Id" (см. Определение class Movie). «repeatitems: false» говорит, что каждое поле данных, которое мы хотим идентифицировать по имени поля (определено в colModel) вместо определения по умолчанию для каждой позиции. Определение root немного странно, но оно определяет, как найти 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#additions_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, если вы выберете в левой части дерева «Отображение данных», а затем «Оптимизация данных»)

P.S .: О 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).

0 голосов
/ 27 мая 2010

Олег

Есть ли у вас пример, о котором вы говорили, когда я работаю с jqgrid / asp.net mvc и безмятежным сервисом, и у меня много времени. Это помогло бы увидеть пример, как я на стене. Thx

SEM

0 голосов
/ 14 мая 2010

Я столкнулся с той же проблемой.Я пришел к выводу, что маршруты мешали сервисному вызову.Вы пробовали Route Debugger Фила Хаака ?Это спасло мой бекон пару раз.

В итоге я создал конечную точку на одном из контроллеров.

0 голосов
/ 14 мая 2010

Это связано с тем, что зарегистрированный маршрут в global.asax не будет распознавать этот файл .svc. он попытается найти этот контроллер с действием getmovies и потерпит неудачу. попробуйте отладку с помощью firebug. Вы можете исправить это, проигнорировав этот маршрут в global.asax

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...