2010-05-14 2 views
2

Это часть вопроса previous.jQuery с ASP.NET MVC - вызов веб-службы с включенным ajax

Теперь я пытаюсь сделать вызов веб-службы, поддерживаемой AJAX, которую я определил в приложении ASP.NET MVC (т. Е. MovieService.svc). Но служба никогда не вызывается в моей функции javascript getMovies.

Эта же методика вызова веб-службы 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(); 
     } 

    } 
} 
+0

Вы можете показывать список маршрутов? Вам, вероятно, нужен IgnoreRoute для MovieService.svc – Joel

+0

Я отредактировал свой ответ, чтобы показать маршруты. Я добавил IgnoreRoute для MovieService, но ничего не изменил, веб-сервис все еще не вызывается. – dcp

+0

Не могли бы вы разместить прототип (интерфейс) функции GetMovies внутри MovieService.svc. Проблема в вашем коде понятна. Я бы немного переписал ваш код и упростил (и устранил вашу основную проблему). – Oleg

ответ

11

Ваша основная проблема заключается в том, что вы используете не абсолютные 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() - doesn't serialize javascript Date objects?). Чтобы сделать меньше проблем в начале, я определяю 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 }); 

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, , , sortable и не очень важны в этом примере, я выбрал там, потому что 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» (см определения 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#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 есть функции, такие как paging, Сортировка и два вида поиск (более как фильтр с WHERE в соответствующем SELECT) данных: простой и продвинутый. Если мы хотим, чтобы эти полезные свойства внутри из jqGrid на страницах нашего сайта мы должны определить в Web Service дополнительный метод, как

[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 если вы Choos e в левой части дерева «Отображение данных», а затем «Оптимизация данных»)

P.S .: О jsonReader вы можете узнать больше о http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data#json_data. Один мой старый ответ Mapping JSON data in 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

@ Oleg - Да, я новичок в jqGrid, но я стараюсь его изучить, но его очень сложно использовать, а примеры плохие. Однако я не понимаю вашего ответа. У меня уже работало с использованием типа данных: «json» и управления потоком управления контроллером. Я пытался заставить его работать с вызовом веб-службы. Это работает в моем проекте, отличном от MVC, но в MVC это не работает, что, по-видимому, указывает на то, что MVC запутывает вещи где-то. – dcp

+0

@ Oleg - Я должен был понять, что имел в виду, когда сказал, что примеры плохие. Сами примеры JQGrid очень хороши, но они все в php, их нет в asp.net. Думаю, это связано с тем, что они хотят, чтобы вы купили коммерческий контроль :). – dcp

+0

Я использую jqGrid в проекте, написанном в ASP.NET MVC, с помощью службы RESTfull WCF, которая является частью одного и того же сайта ASP.NET. Поэтому мы используем ту же технику. Я немного поиграю с дочерью и отправлю вам пример – Oleg

0

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

+0

Это не имело значения. Я добавил маршруты. IgnoreRoute («* MovieService.svc *»); к RegisterRoutes, а также попробовал его с маршрутами. IgnoreRoute («MovieService.svc/GetMovies»). Ничего не сработало. – dcp

+0

Вы пытались получить доступ к сервису из браузера? –

+0

Из того, что я могу сказать, работает в браузере. Конечно, мы не можем вызывать веб-методы WCF из браузера (в отличие от веб-методов asmx). – dcp

0

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

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

+0

Да, я только что пробовал отладчик маршрута и маршрут. Как я уже сказал в своем ответе Олегу, я думаю, что MVC просто что-то шланги, когда пытается позвонить в веб-сервис. Приятно знать, что у кого-то была такая же проблема и что я не одинок :). – dcp

0

Олег,

У вас есть пример вы говорите, как я работаю с jqgrid/ASP.NET MVC и успокоительной службы и имеющие нахала о времени. Это поможет увидеть пример, как я на стене. Thx

SEM

Смежные вопросы