昨天我写了一个网络方法来返回报告的问题:
<WebService(Namespace:="http://maggie/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<ScriptService()> _
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Public Class _Raphael
Inherits System.Web.Services.WebService
<WebMethod()> _
<ScriptMethod(ResponseFormat:=ResponseFormat.Json, UseHttpGet:=True)> _
Public Function GetReportedProblems(ByVal pathname As String) As Hashtable
当我尝试使用Web方法时,出现以下错误:
不支持System.Collections.Hashtable类型,因为它实现了IDictionary。
quick google search让我意识到,我显然不应该在没有我做某些工作的情况下通过.Net序列化{。}}。
我的困惑源于这样一个事实:我通常使用HashTable
个对象作为我的网络方法的回报(主要是因为它非常接近JavaScript对象,非常方便)。
我写的一个Web方法示例返回HashTable
(工作正常)
HashTable
我填充<ScriptService()> _
Partial Class _Lugash_Gopher
Inherits ppcBasePage 'which inherits System.Web.UI.Page
<WebMethod()> _
<ScriptMethod(ResponseFormat:=ResponseFormat.Json)> _
Public Shared Function GetAgentsPaged(ByVal iDisplayStart As Integer, ByVal iDisplayLength As Integer, ByVal sEcho As Integer, ByVal TeamID As Integer) As Hashtable
(HashTable
),如下所示:
h
返回(示例):
h.Add("TeamID", TeamID) 'Integer
h.Add("sEcho", sEcho) 'Integer (blame DataTables.Net for the "s" prefix)
h.Add("iTotalRecords", iTotalRecords) 'Integer
h.Add("iTotalDisplayRecords", iTotalDisplayRecords) 'Integer
h.Add("aaData", Helpers.ConvertDataTableToJSON(ds.Tables(1))) 'Method returns System.Array
方法{
"d": {
"iTotalRecords": 2,
"iTotalDisplayRecords": 10,
"team_name": "All Teams",
"aaData": [{
"next_due_date": "01/01/2014",
"ready_feedback": 0,
"emp_name": "John Doe",
"row": 1,
"incomplete_feedback": 1,
"emp_id": 1
}, {
"next_due_date": "01/14/2014",
"ready_feedback": 0,
"emp_name": "Jane Smith",
"row": 2,
"incomplete_feedback": 1,
"emp_id": 2
}],
"sEcho": 1,
"TeamID": 1
}
}
位于GetReportedProblems
代码隐藏中,允许.asmx
。
方法GET
位于GetAgentsPaged
代码隐藏中,需要.aspx
。
这是我可以在方法结构中确定的唯一两个差异。
为什么我可以在POST
代码隐藏中使用HashTable
作为Web方法的返回类型,而不是在.aspx
代码隐藏中使用?
答案 0 :(得分:1)
我在fórum找到了问题的答案。但是你已经从你所描述的内容中找到了答案的一部分。
所以你要问的下一个重要问题是,为什么一个简单的ASPX可以完成ASMX无法做到的工作呢?答案是因为ASMX主要是基于XML的,所有与ASMX的通信都基于SOAP。为了它的工作,通过ScriptManager使用ASP.NET(我相信你正在做的事情)微软聪明地开发了和Handler:
(...)要从脚本启用Web服务调用,必须在应用程序的Web.config文件中注册ScriptHandlerFactory HTTP处理程序。处理程序处理从脚本调用的调用.asmx Web服务。以下示例显示了用于添加处理程序的Web.config元素。(...)
但是在剩下的时间里,Web服务仍然是基于XML的,就像应该这样:
(...)对于非ASP.NET AJAX脚本发出的Web服务调用,ScriptHandlerFactory处理程序将调用委托给使用SOAP而不是JSON格式的默认处理程序。委派是自动执行的,除非您要禁用Web协议的SOAP协议,否则不必执行任何操作。在这种情况下,您必须在Web.config文件中输入以下配置设置。 (...)
(...)要在ASP.NET网页中启用从客户端脚本调用.asmx Web服务,必须向页面添加ScriptManager控件。通过向ScriptManager控件添加asp:ServiceReference子元素,然后将服务器引用路径属性设置为Web服务的URL来引用Web服务。 ServiceReference对象指示ASP.NET生成一个JavaScript代理类,用于从客户端脚本调用指定的Web服务。(...)
注意:此信息摘自here。
继续,那么为什么在ASMX Web Service中收到该错误?好吧,你得到了这个错误,因为编译器告诉你这个&#34;嘿,有人叫我(xml web服务),大多数时候我可能会回复XML和Hashtables实现IDictionary不能转换为XML!& #34;,如果你有办法告诉编译器&#34;嘿,但我保证只通过ScriptManager从ASP.NET页面调用你(xml ws),ScriptManager通过ASP实现的代理与你交谈。 NET Handler&#34;那么你的代码会起作用,但是ASMX WebService不允许你执行这样的配置!
这就是为什么XML WebServices(asmx)拖欠该错误,而ASP.NET没有,因为ASP.NET不响应XML,它会响应您希望它响应的内容,因为开发人员可以任意决定是否要发送响应JSON,HTML,XML,Text或仅基于二进制。
如果我是你,我会向前迈一步,我会尝试指定你的Web方法输出XML(在你的ASP.NET页面中),看看它是否会引发你同样的错误,我没有&#39尝试过这个,但肯定会发生这种情况。
更新1
请注意,标签ScriptService不指定继承,它只是一个注释,可能就是ScriptHandler检测到它应该拦截的XML WebService调用的方式!类的本质由其继承定义,该继承基于WebService类(特定于XML WebServices)。所以前面这种类型的注释&#39; ScriptMethod&#39;也特定于ScriptHandler,因为它们指定了如何转换Web服务的答案,以便将其发送到在ASP.NET页面中注册的ScriptManager!
如果您认为Web服务应该为您做更多事情,我建议您强烈关注WCF服务(即Indigo服务(代号)),您可以找到有关此here的更多信息。尝试之后,再也不会使用XML WebServices :),它在配置部分有一点学习曲线,但之后就是纯粹的工作质量!关于WCF的一本好书是WCF by Jonh Sharp,当然我个人认为。顺便说一下,非常好的和相关的问题!
更新2
对我的here陈述类似的回应,它说:
(...)通过[ScriptMethod]向JavaScript公开的服务使用了不同的序列化程序(JavaScriptSerializer),但没有此限制。
当您从JavaScript调用服务时,您将调用JSON端点(使用[ScriptMethod]声明)。但是,当您从浏览器进行测试时,您将达到传统的XML连接点(使用[WebMethod]声明)。的(...)强>
一种解决方法是让你使用JavaScriptSerializer将Hashtable序列化为JSON(在web方法中),然后你的web方法将返回一个String,但这有点......糟糕!如果你打算构建既可维护又可扩展的东西,那么你可能会更好地使用WCF服务。
更新3
为了更好地指导我对你的评论的回答,是的,你不能序列化Hashtables,因为&#34; XmlSerializer不能处理实现IDictionary接口的类#34; (在某些情况下,XML WebServices最终使用XML Serializer,并且当从堆栈底部抛出异常时,直到它到达您的代码为止):
<强>(...)强> 问:为什么我不能序列化哈希表? 答:XmlSerializer无法处理实现IDictionary接口的类。这部分是由于计划约束,部分原因是哈希表在XSD类型系统中没有对应物。唯一的解决方案是实现一个不实现IDictionary接口的自定义哈希表。的(...)强>
此摘录摘自此Microsoft资源here,它位于页面底部附近。