JSON数据绑定DropdownList报错,问题在WebMethod还是前端处理?
问题描述
通过WebMethod生成了如下JSON数据:
[ { "id": 367, "location": "Gagra" }, { "id": 368, "location": "Gudauta" }, { "id": 369, "location": "Sukhumi" }, { "id": 370, "location": "Gulripshi" }, { "id": 371, "location": "Ochamchira" }, { "id": 372, "location": "Tkvarcheli" }, { "id": 373, "location": "Gali" } ]
对应的WebMethod代码:
<WebMethod()> Public Function PopulateStates(ByVal idLocation As Integer) As String Dim Locations As List(Of LocationData) = New List(Of LocationData) Dim JSONString As String Dim adp As New StatesTableAdapter Dim ds As StatesDataTable = adp.GetStatesByCountry(idLocation) If ds.Rows.Count > 0 Then For Each row As StatesRow In ds Dim ld As LocationData = New LocationData With { .id = row.idState, .location = row.locName } Locations.Add(ld) Next End If JSONString = JsonConvert.SerializeObject(Locations, Formatting.Indented) Return JSONString End Function Public Class LocationData Public Property id As Integer Public Property location As String End Class
前端AJAX调用代码:
$('#ddlCountry').change(function (e) { $.ajax({ type: "POST", url: "/TestWebService.asmx/PopulateStates", contentType: "application/json; charset=utf-8", data: '{"idLocation":"' + $(this).val() + '"}', dataType: "json", success: function (result, status, xhr) { console.log(result.d); $.each(result.d, function (key, value) { $("#ddlState").append($("<option></option>").val(value.id).html(value.location)); }); }, error: function (xhr, status, error) { alert("Result: " + status + " " + error + " " + xhr.status + " " + xhr.statusText) } }); });
执行时出现错误:Uncaught TypeError: Cannot use 'in' operator to search for 'length' in [,请问问题出在WebMethod还是前端处理环节?
问题原因与解决方案
问题出在WebMethod和前端处理的双重问题,核心是JSON序列化重复:
WebMethod端问题:
ASMX WebMethod默认会自动将返回对象序列化为JSON,但你手动用JsonConvert.SerializeObject把列表转成了JSON字符串,导致最终返回的是字符串形式的JSON,而非原生JSON对象。前端拿到的result.d是带格式的字符串,不是可直接遍历的数组。前端处理问题:
直接用$.each遍历字符串,$.each要求遍历目标是数组或对象,字符串被当作普通文本处理时,就会触发in运算符查找length的错误。
修复方案
方案1:修改WebMethod,直接返回对象列表(推荐)
去掉手动序列化步骤,让WebMethod自动处理JSON转换:
<WebMethod()> Public Function PopulateStates(ByVal idLocation As Integer) As List(Of LocationData) Dim Locations As List(Of LocationData) = New List(Of LocationData) Dim adp As New StatesTableAdapter Dim ds As StatesDataTable = adp.GetStatesByCountry(idLocation) If ds.Rows.Count > 0 Then For Each row As StatesRow In ds Dim ld As LocationData = New LocationData With { .id = row.idState, .location = row.locName } Locations.Add(ld) Next End If ' 直接返回列表,WebMethod自动序列化为JSON数组 Return Locations End Function Public Class LocationData Public Property id As Integer Public Property location As String End Class
方案2:保留WebMethod返回字符串,前端手动解析JSON
在success回调里先把字符串解析为JSON数组:
success: function (result, status, xhr) { console.log(result.d); // 解析字符串为JSON数组 var states = JSON.parse(result.d); $.each(states, function (key, value) { $("#ddlState").append($("<option></option>").val(value.id).html(value.location)); }); }
另外,前端AJAX的data参数中,idLocation应传数值类型,建议修改为:
data: JSON.stringify({ idLocation: parseInt($(this).val()) })
保证参数类型与WebMethod的Integer匹配,避免潜在的参数解析问题。
内容的提问来源于stack exchange,提问作者Jeff Hurley
相关产品推荐
相关产品推荐

