在 WCF/.NET 中返回数据表
-
08-06-2019 - |
题
我有一个 WCF 服务,我想从中返回一个数据表。我知道,就返回 DataTable 是否是一个好的实践而言,这通常是一个备受争议的话题。让我们暂时把它放在一边。
当我从头开始创建数据表时,如下所示,没有任何问题。该表已创建、填充并返回给客户端,一切顺利:
[DataContract]
public DataTable GetTbl()
{
DataTable tbl = new DataTable("testTbl");
for(int i=0;i<100;i++)
{
tbl.Columns.Add(i);
tbl.Rows.Add(new string[]{"testValue"});
}
return tbl;
}
但是,一旦我出去并点击数据库来创建表,如下所示,我就会收到 CommunicationException“底层连接已关闭:连接意外关闭。”
[DataContract]
public DataTable GetTbl()
{
DataTable tbl = new DataTable("testTbl");
//Populate table with SQL query
return tbl;
}
该表已在服务器端正确填充。它比我循环并返回的测试表小得多,并且查询小而快 - 这里不存在超时或大数据传输的问题。使用完全相同的函数和 DataContracts/ServiceContracts/BehaviorContracts。
为什么表的填充方式会对表的成功返回产生影响?
解决方案
对于有类似问题的人,我已经解决了我的问题。这是好几倍。
- 正如 Darren 建议和 Paul 支持的那样,配置中的 Max..Size 属性需要放大。SvcTraceViewer 实用程序有助于确定这一点,但它仍然不总是给出最有用的错误消息。
- 似乎当服务引用在客户端更新时,配置有时无法正确更新(例如更改服务器上的配置值并不总是能在客户端上正确更新。在调试过程中,我必须在客户端和服务器端多次更改 Max..Size 属性)
为了使 DataTable 可序列化,需要为其指定一个名称。默认构造函数不会给表命名,因此:
return new DataTable();
将不可序列化,同时:
return new DataTable("someName");
将为表命名任何作为参数传递的内容。
请注意,可以随时通过将字符串分配给表来给表命名。
TableName
数据表的属性。var table = new DataTable(); table.TableName = "someName";
希望这会对某人有所帮助。
其他提示
诊断此类 WCF 错误(实际上无法告诉您太多信息的错误)的最佳方法是启用跟踪。在您的 web.config 文件中,添加以下内容:
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Information"
propagateActivity="true">
<listeners>
<add name="ServiceModelTraceListener"
type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
initializeData="wcf-traces.svclog"/>
</listeners>
</source>
</sources>
</system.diagnostics>
然后,您可以在 .NET Framework SDK(或使用 Visual Studio)中提供的 SvcTraceViewer.exe 实用程序中打开生成的文件。在我的计算机上,可以在 %PROGRAMFILES%\Microsoft SDKs\Windows\v6.0A\Bin\SvcTraceViewer.exe 中找到它。
只需查找错误消息(以粗体红色显示),它就会具体告诉您问题所在。
我将 Datable 添加到数据集中并返回表格,如下所示......
DataTable result = new DataTable("result");
//linq to populate the table
Dataset ds = new DataSet();
ds.Tables.Add(result);
return ds.Tables[0];
希望能帮助到你 :)
除了为所有绑定属性设置最大值之外。
确保您从 Web 服务传递/返回的每个表都必须有一个表名,这意味着 table.tablename
属性不应为空。
您想要的属性是OperationContract(在接口上)/操作行为(在方法上):
[ServiceContract]
public interface ITableProvider
{
[OperationContract]
DataTable GetTbl();
}
[OperationBehavior]
public DataTable GetTbl(){
DataTable tbl = new DataTable("testTbl");
//Populate table with SQL query
return tbl;
}
另外,在...我认为服务配置...您想要指定可以发送错误。您可能会遇到诸如消息大小太大之类的错误。您可以通过修改读者配额等来解决这个问题。
默认情况下,wsHttpBinding 的接收大小配额约为 65 KB,因此,如果序列化数据表的 XML 超过此限制,则会抛出错误(我 95% 确信数据表中的数据超过 65 KB) )。
您可以在以下位置更改读者配额等设置 web.config
/ app.config
或者您可以在代码中的绑定实例上设置它。但是,是的,如果您默认情况下没有更改它,这可能就是您的问题所在。
WSHttpBindingBase 成员 - 查看 ReaderQuotas 属性以及 MaxReceivedMessageSize 属性。
您可能超出了配额 - 数据表大于连接允许的最大数据包大小。
你可能需要设置 最大接收消息大小 和 最大缓冲区大小 为您的连接带来更高的价值。
返回类型失败的原因有 3 个: datatable
在 WCF 服务中
您必须指定数据表名称,例如:
MyTable=new DataTable("tableName");
当您在 WCF 服务的客户端添加引用时,选择可重用 dll
system.data
指定属性
datatable
成员变量如[DataMember] public DataTable MyTable{ get; set; }
我认为 Darren 很可能是正确的 - 为 WCF 提供的默认值小得可笑,如果您遇到它们,您最终会遇到难以追踪的错误。当您尝试执行简单测试用例之外的任何操作时,它们似乎就会出现。我浪费了比我愿意承认的调试问题更多的时间,这些问题最终证明与客户端和服务器上的各种配置(大小)设置有关。我想我最终修改了几乎所有的内容,例如。MaxBufferPoolSize、MaxBufferSize、MaxConnections、MaxReceivedMessageSize 等
话虽如此,提到的 SvcTraceViewer 实用程序也很棒。我确实遇到过一些情况,它没有我希望的那么有帮助,但总的来说,它是分析通信流和错误的一个很好的工具。