为什么我不能始终将`HashTable'序列化?

时间:2014-06-04 14:55:48

标签: asp.net vb.net

昨天我写了一个网络方法来返回报告的问题:

<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代码隐藏中使用?

1 个答案:

答案 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,它位于页面底部附近。