AjaxToolkit CascadingDropdown子级下拉框不加载,knownCategoryValues为空
问题描述
我使用AjaxToolkit的CascadingDropdown控件搭配三个DropDownList,数据从ASMX WebService获取。第一个下拉框可正常加载,但选择父级选项后,子级下拉框无法加载,甚至无法触发断点。在Visual Studio中测试ASMX WebService能得到预期结果,但在应用中,填充子级下拉框的Web方法未被调用,本应携带父级选中项键值对的knownCategoryValues参数为空。已尝试重装AjaxToolkit、检查引用、添加服务引用,仍未解决。
排查与解决建议
- 补全Web服务方法的参数:CascadingDropdown要求Web方法必须包含
string knownCategoryValues和string category两个参数,当前子级方法(GetEmpresaAcceso、GetPuestoAcceso)只定义了knownCategoryValues,缺少category参数,这会导致控件无法正常发起请求。修改方法签名如下:[WebMethod] public CascadingDropDownNameValue[] GetEmpresaAcceso(string knownCategoryValues, string category) { // 现有逻辑保持不变 } - 验证[ScriptService]特性:确保ASMX类上的
[ScriptService]特性未被注释或遗漏,这是AJAX能够调用Web服务的核心配置。 - 检查路径与方法名拼写:确认CascadingDropdown的
ServicePath(如~/services/WebService1.asmx)与实际文件路径一致,ServiceMethod与Web服务中的方法名大小写、拼写完全匹配。 - 用浏览器开发者工具排查请求:按F12打开开发者工具,切换到「网络」面板,选择父级下拉框选项,观察是否有AJAX请求发出:
- 若没有请求:说明控件的事件绑定存在问题,检查页面是否引入了正确的AjaxToolkit脚本。
- 若有请求但报错:查看请求的状态码(如404表示路径错误,500表示服务端异常),根据响应内容定位问题。
- 修复SQL注入风险:当前代码使用字符串拼接SQL语句,存在严重安全隐患,同时可能因参数格式问题导致数据库查询失败。改为参数化查询:
string sql = "SELECT * FROM GetEmpresasAccesoUsuario(@CodigoUser, @Pais)"; OleDbCommand cmd = new OleDbCommand(sql, dbCon); cmd.Parameters.AddWithValue("@CodigoUser", _codigoUser); cmd.Parameters.AddWithValue("@Pais", pais); - 优化GetData方法:将
private修饰的GetData改为支持参数化查询的重载版本,提升代码安全性和可维护性。
相关代码
ASPX页面标记
<div class="card-body"> <div class="row mb-2 d-flex flex-column"> <div class="col"> <div class="form-group"> <label class="form-label">País</label> <asp:DropDownList ID="ddlPais" runat="server" CssClass="form-select form-select-sm" ></asp:DropDownList> <ajaxToolkit:CascadingDropDown ID="cdlPais" TargetControlID="ddlPais" PromptText="Seleccione País" PromptValue="" ServicePath="~/services/WebService1.asmx" ServiceMethod="GetPaisAcceso" runat="server" Category="CategoryPais" LoadingText="Cargando..." /> </div> </div> <div class="col"> <div class="form-group"> <label class="form-label">Empresa</label> <asp:DropDownList ID="ddlEmpresa" runat="server" CssClass="form-select form-select-sm" ></asp:DropDownList> <ajaxToolkit:CascadingDropDown ID="cdlEmpresa" TargetControlID="ddlEmpresa" PromptText="Seleccione Empresa" PromptValue="" ServicePath="~/services/WebService1.asmx" ServiceMethod="GetEmpresaAcceso" runat="server" ParentControlID="ddlPais" Category="CategoryEmpresa" LoadingText="Cargando..." /> </div> </div> <div class="col"> <div class="form-group"> <label class="form-label">Puesto</label> <asp:DropDownList ID="ddlPuesto" runat="server" CssClass="form-select form-select-sm"></asp:DropDownList> <ajaxToolkit:CascadingDropDown ID="cdlPuesto" TargetControlID="ddlPuesto" PromptText="Seleccione Puesto" PromptValue="" ServicePath="~/services/WebService1.asmx" ServiceMethod="GetPuestoAcceso" ParentControlID="ddlEmpresa" runat="server" Category="CategoryPuesto" LoadingText="Cargando..." /> </div> </div> <div class="col"> <hr /> <asp:Button ID="btnGuardar" runat="server" CssClass="btn btn-success" OnClick="btnGuardar_OnClick" Text="Guardar Cambios" /> </div> </div> </div>
修正后的ASMX WebService代码
using AjaxControlToolkit; using FACTURACION_CLASS; using Microsoft.VisualBasic; using Microsoft.VisualBasic.CompilerServices; using System; using System.Collections.Generic; using System.Data; using System.Data.OleDb; using System.Web; using System.Web.Script.Services; using System.Web.Services; namespace WebAppVB.services { [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [ScriptService] public class WebService1 : WebService { private readonly seguridad _seguridad = new seguridad(); private readonly database _database = new database(); private string _codigoUser = HttpContext.Current.Request.Cookies["CodigoUser"]?.Value; [WebMethod] public CascadingDropDownNameValue[] GetPaisAcceso(string knownCategoryValues, string category) { string sql = "SELECT * FROM GetPaisesAccesoUsuario(@CodigoUser)"; List<CascadingDropDownNameValue> paises = GetData(sql, new OleDbParameter("@CodigoUser", _codigoUser)); return paises.ToArray(); } [WebMethod] public CascadingDropDownNameValue[] GetEmpresaAcceso(string knownCategoryValues, string category) { string pais = CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues)["CategoryPais"]; string sql = "SELECT * FROM GetEmpresasAccesoUsuario(@CodigoUser, @Pais)"; List<CascadingDropDownNameValue> empresas = GetData(sql, new OleDbParameter("@CodigoUser", _codigoUser), new OleDbParameter("@Pais", pais)); return empresas.ToArray(); } [WebMethod] public CascadingDropDownNameValue[] GetPuestoAcceso(string knownCategoryValues, string category) { string empresa = CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues)["CategoryEmpresa"]; string sql = "SELECT * FROM GetPuestosAccesoUsuario(@CodigoUser, @Empresa)"; List<CascadingDropDownNameValue> puestos = GetData(sql, new OleDbParameter("@CodigoUser", _codigoUser), new OleDbParameter("@Empresa", empresa)); return puestos.ToArray(); } private List<CascadingDropDownNameValue> GetData(string sql, params OleDbParameter[] parameters) { List<CascadingDropDownNameValue> values = new List<CascadingDropDownNameValue>(); using (OleDbConnection dbCon = new OleDbConnection(_seguridad.conn)) { dbCon.Open(); OleDbCommand cmd = new OleDbCommand(sql, dbCon); cmd.Parameters.AddRange(parameters); using (OleDbDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { values.Add(new CascadingDropDownNameValue { name = reader[1].ToString(), value = reader[0].ToString() }); } return values; } } } } }
内容的提问来源于stack exchange,提问作者Gabriel Z
相关产品推荐
相关产品推荐

