带有 ASP.NET MVC 的 jquery - 调用启用 ajax 的 Web 服务
Posted
技术标签:
【中文标题】带有 ASP.NET MVC 的 jquery - 调用启用 ajax 的 Web 服务【英文标题】:jquery with ASP.NET MVC - calling ajax enabled web service 【发布时间】:2011-02-19 15:03:09 【问题描述】:这是previous问题的延续。
现在我正在尝试调用我在 ASP.NET MVC 应用程序中定义的启用 AJAX 的 Web 服务(即MovieService.svc
)。但是我的getMovies
javascript 函数中从未调用过该服务。
如果我在非 ASP.NET MVC 应用程序中尝试这种调用 AJAX Web 服务的相同技术,它可以正常工作,所以我想知道当它尝试创建 AJAX 时,ASP MVC 路由是否会以某种方式干扰事物网络服务调用。
你知道为什么我的网络服务没有被调用吗?代码如下。
<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();
【问题讨论】:
你能显示你的路线吗?您可能需要一个 IgnoreRoute 用于 MovieService.svc 我已编辑我的回复以显示路线。我为 MovieService 添加了 IgnoreRoute,但它没有改变任何东西,仍然没有调用 Web 服务。 您能否在 MovieService.svc 中发布 GetMovies 函数的原型(接口)。您的代码中的问题很清楚。我会重写一点你的代码,让它更容易(并解决你的主要问题)。 有趣。刚刚用一个新的测试项目尝试了这个,可以确认行为。似乎不是路由问题,因为您可以直接浏览到 Web 服务。当我有更多时间时,我将不得不玩一下,看看我是否能解决这个问题。 我希望我的代码能在你的环境中运行。我对路由没有任何问题,但routes.IgnoreRoute("*MovieService.svc*")
似乎是个好主意。如果某些东西不适用于 MVC/WFC,我们可以比较您和我的项目中的更多部分。再说一句:你怎么能看到我的英文不好,所以如果你发现一些明显的错误,请编辑我的答案并修复这些。
【参考方案1】:
您的主要问题是您在 ajax
调用中使用的不是绝对 URL。 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
中更直接地读取从Web 服务器返回的数据。
更新: 在我看来,我将在稍后描述编辑功能,并在这里解释如何获取 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()
像对象数组Movie
一样返回JSON 数据。所以 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)和服务器必须返回已排序的数据。有关详细信息,请参阅http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options 上的prmNames
参数说明和http://www.trirand.com/jqgridwiki/doku.php?id=wiki:singe_searching 上的sopt
参数说明。
关于datatype: 'json'
,我们定义jQuery.ajax
的dataType: 'json'
参数(不要混淆datatype
参数内部的大小写)。 colModel
内所有字段的名称我们定义 exact 与 JSON 对象内的字段名称相同。一些附加参数viewrecords
、rownumbers
、sortable
和headertitles
在此示例中不是很重要,我选择那里是因为 1)我喜欢那里 2)我设置了 rowNum: 0
以使选项 @987654367 成为可能@ 工作正常,如果 rowNum: 5
像您的原始示例一样,不会向我们显示以 -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 数据中找到 rows 的 root。 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
。所以我们无法进行数据分页。您可以使用定义page
、total
和records
(也作为函数)的函数来扩展jsonReader
,例如
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 的灵活性。仅当您访问无法更改的 Web 服务器时,才应使用所述方式。 jqGrid具有分页、排序和两种搜索(更多是在相应的SELECT中使用WHERE过滤)数据:简单和高级.如果我们想在我们的网页上的 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 上阅读有关这种数据传输的更多信息)
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 下载源代码。对比一下你的项目,尤其是jqGrid的参数为完整url的部分和描述WCF服务接口的web.config部分。
UPDATED 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)。
【讨论】:
@Oleg - 是的,我是 jqGrid 的新手,但我正在努力学习它,但它很难使用,而且示例很差。虽然我不太明白你的回答。我已经使用 datatype: 'json' 让控制流向控制器。我试图让它与对 Web 服务的调用一起工作。这在我的非 MVC 项目中有效,但在 MVC 中无效,这似乎表明 MVC 在某处搞砸了。 @Oleg - 当我说这些例子很糟糕时,我应该说明我的意思。 JQGrid 的例子本身就很好,但是都是用php 写的,asp.net 里没有。我想这是因为他们希望你购买商业控制 :)。 我在一个用 ASP.NET MVC 编写的项目中使用 jqGrid,该项目带有一个 RESTfull WCF 服务,该服务是同一个 ASP.NET 站点的一部分。所以我们使用相同的技术。我和我女儿玩了一会儿,给你举个例子 @Oleg - 感谢您的大力帮助。我很快就会尝试你的解决方案,我只是还没有机会,因为我一直忙于其他一些项目。我会让你知道我发现了什么。再次感谢您的详细解释。 @Oleg - 这是 VS 2010 解决方案吗?我只有 VS 2008,所以我无法打开解决方案文件:(。无论如何,你已经花了足够的时间,我会继续接受答案,这样你就可以得到你的代表点。【参考方案2】:这是因为 global.asax 中注册的路由不会识别这个 .svc 文件。它将尝试使用操作 getmovies 搜索该控制器并且将失败。尝试使用 firebug 进行调试。 您可以通过忽略 global.asax 中的这条路线来解决此问题
【讨论】:
没什么区别。我添加了 routes.IgnoreRoute("MovieService.svc");到 RegisterRoutes,还尝试了 routes.IgnoreRoute("MovieService.svc/GetMovies")。都没有用。 你试过从浏览器访问服务吗? 据我所知,它在浏览器中可以正常工作。当然,我们不能从浏览器调用 WCF 网络方法(不像 asmx 网络方法)。【参考方案3】:我遇到了同样的问题。我得出的结论是路由干扰了服务调用。你试过 Phil Haack 的Route Debugger 吗?它救了我几次培根。
最后,我在其中一个控制器上创建了一个端点。
【讨论】:
是的,我刚刚尝试了路由调试器并且路由匹配。正如我在回复 Oleg 时所说的那样,我认为 MVC 只是在尝试调用 Web 服务时把事情搞砸了。很高兴知道其他人也有同样的问题,而且我并不孤单:)。【参考方案4】:奥列格,
当我正在使用 jqgrid/asp.net mvc 和一个安静的服务并且有一个时间问题时,您是否有您正在谈论的示例。当我在墙上时,这将有助于看到一个例子。谢谢
扫描电镜
【讨论】:
以上是关于带有 ASP.NET MVC 的 jquery - 调用启用 ajax 的 Web 服务的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET MVC - 使用带有匿名类型和 Jquery 的 JavaScriptStringEncode()
带有 jquery 代码的脚本块应该放在 ASP.NET MVC 母版页的啥位置?
带有 ASP.NET MVC 的 jquery - 调用启用 ajax 的 Web 服务
如何在带有 ADO.NET 的 ASP.NET Core MVC 中使用 jQuery Ajax 自动完成